From 8ea00aed64e70951cecfc6fdf2e3f3dff712a804 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Tue, 31 Oct 2017 11:35:15 -0700 Subject: [PATCH 001/102] 8190227: Forward port 8188880 to JDK10CPU Reviewed-by: dfuchs, lancea, rriggs --- .../impl/xs/traversers/SchemaContentHandler.java | 12 ++++++++++-- .../internal/impl/xs/traversers/XSDHandler.java | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/SchemaContentHandler.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/SchemaContentHandler.java index f603ddf6d61..455522f0f13 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/SchemaContentHandler.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/SchemaContentHandler.java @@ -26,6 +26,7 @@ import com.sun.org.apache.xerces.internal.util.NamespaceSupport; import com.sun.org.apache.xerces.internal.util.SAXLocatorWrapper; import com.sun.org.apache.xerces.internal.util.SymbolTable; import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; +import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; import com.sun.org.apache.xerces.internal.util.XMLSymbols; import com.sun.org.apache.xerces.internal.xni.NamespaceContext; import com.sun.org.apache.xerces.internal.xni.QName; @@ -78,6 +79,7 @@ final class SchemaContentHandler implements ContentHandler { private final QName fAttributeQName = new QName(); private final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); private final XMLString fTempString = new XMLString(); + private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); /** *

Constructs an SchemaContentHandler.

@@ -103,6 +105,7 @@ final class SchemaContentHandler implements ContentHandler { */ public void startDocument() throws SAXException { fNeedPushNSContext = true; + fNamespaceContext.reset(); try { fSchemaDOMParser.startDocument(fSAXLocatorWrapper, null, fNamespaceContext, null); } @@ -326,7 +329,11 @@ final class SchemaContentHandler implements ContentHandler { if (nsPrefix.length() > 0) { prefix = XMLSymbols.PREFIX_XMLNS; localpart = nsPrefix; - rawname = fSymbolTable.addSymbol(prefix + ":" + localpart); + fStringBuffer.clear(); + fStringBuffer.append(prefix); + fStringBuffer.append(':'); + fStringBuffer.append(localpart); + rawname = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); } else { prefix = XMLSymbols.EMPTY_STRING; @@ -334,7 +341,8 @@ final class SchemaContentHandler implements ContentHandler { rawname = XMLSymbols.PREFIX_XMLNS; } fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI); - fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, nsURI); + fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, + (nsURI != null) ? nsURI : XMLSymbols.EMPTY_STRING); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java index 8fbb73db288..d9898b2157a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java @@ -2266,6 +2266,8 @@ public class XSDHandler { fSecurityManager.isSecureProcessing()); try { + parser.setFeature(NAMESPACE_PREFIXES, true); + namespacePrefixes = true; // If this is a Xerces SAX parser set the security manager if there is one if (parser instanceof SAXParser) { if (fSecurityManager != null) { From 29534320cdfd11f0a48b20fde4169bd9b178da58 Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Thu, 7 Dec 2017 11:21:47 -0800 Subject: [PATCH 002/102] 8187496: Possible memory leak in java.apple.security.KeychainStore.addItemToKeychain Reviewed-by: weijun, mullan, ahgross --- .../native/libosxsecurity/KeystoreImpl.m | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index 9df3e3c9562..e678bce28de 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -438,12 +438,11 @@ JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyDa if (passwordChars == NULL) { goto errOut; } - passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen); - // clear the password and release - memset(passwordChars, 0, passwordLen); - (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars, - JNI_ABORT); + passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull); + if (passwordStrRef == NULL) { + goto errOut; + } } } @@ -471,7 +470,12 @@ JNIEXPORT jbyteArray JNICALL Java_apple_security_KeychainStore__1getEncodedKeyDa errOut: if (exportedData) CFRelease(exportedData); if (passwordStrRef) CFRelease(passwordStrRef); - + if (passwordChars) { + // clear the password and release + memset(passwordChars, 0, passwordLen); + (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars, + JNI_ABORT); + } return returnValue; } @@ -538,12 +542,11 @@ JNF_COCOA_ENTER(env); if (passwordChars == NULL) { goto errOut; } - passwordStrRef = CFStringCreateWithCharacters(kCFAllocatorDefault, passwordChars, passwordLen); - // clear the password and release - memset(passwordChars, 0, passwordLen); - (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars, - JNI_ABORT); + passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull); + if (passwordStrRef == NULL) { + goto errOut; + } } } @@ -581,7 +584,14 @@ JNF_COCOA_ENTER(env); CFRelease(createdItems); } -errOut: ; +errOut: + if (passwordStrRef) CFRelease(passwordStrRef); + if (passwordChars) { + // clear the password and release + memset(passwordChars, 0, passwordLen); + (*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars, + JNI_ABORT); + } JNF_COCOA_EXIT(env); From 72ac0bfc889f0a9a75f907e2c7deecf1aa591bad Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Thu, 7 Dec 2017 12:25:09 -0800 Subject: [PATCH 003/102] 8192789: Avoid using AtomicReference in sun.security.provider.PolicyFile Reviewed-by: mullan, ahgross --- .../sun/security/provider/PolicyFile.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/PolicyFile.java b/src/java.base/share/classes/sun/security/provider/PolicyFile.java index 587d885d92f..79723602b17 100644 --- a/src/java.base/share/classes/sun/security/provider/PolicyFile.java +++ b/src/java.base/share/classes/sun/security/provider/PolicyFile.java @@ -40,7 +40,7 @@ import javax.security.auth.x500.X500Principal; import java.io.FilePermission; import java.net.SocketPermission; import java.net.NetPermission; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.ConcurrentHashMap; import jdk.internal.misc.JavaSecurityAccess; import static jdk.internal.misc.JavaSecurityAccess.ProtectionDomainCache; import jdk.internal.misc.SharedSecrets; @@ -248,7 +248,8 @@ public class PolicyFile extends java.security.Policy { private static final int DEFAULT_CACHE_SIZE = 1; // contains the policy grant entries, PD cache, and alias mapping - private AtomicReference policyInfo = new AtomicReference<>(); + // can be updated if refresh() is called + private volatile PolicyInfo policyInfo; private boolean expandProperties = true; private boolean allowSystemProperties = true; @@ -268,8 +269,8 @@ public class PolicyFile extends java.security.Policy { * previously parsed and have syntax errors, so that they can be * subsequently ignored. */ - private static AtomicReference> badPolicyURLs = - new AtomicReference<>(new HashSet<>()); + private static Set badPolicyURLs = + Collections.newSetFromMap(new ConcurrentHashMap()); // The default.policy file private static final URL DEFAULT_POLICY_URL = @@ -341,7 +342,7 @@ public class PolicyFile extends java.security.Policy { // System.out.println("number caches=" + numCaches); PolicyInfo newInfo = new PolicyInfo(numCaches); initPolicyFile(newInfo, url); - policyInfo.set(newInfo); + policyInfo = newInfo; } private void initPolicyFile(final PolicyInfo newInfo, final URL url) { @@ -498,7 +499,7 @@ public class PolicyFile extends java.security.Policy { // skip parsing policy file if it has been previously parsed and // has syntax errors - if (badPolicyURLs.get().contains(policy)) { + if (badPolicyURLs.contains(policy)) { if (debug != null) { debug.println("skipping bad policy file: " + policy); } @@ -539,10 +540,7 @@ public class PolicyFile extends java.security.Policy { throw new InternalError("Failed to load default.policy", pe); } // record bad policy file to avoid later reparsing it - badPolicyURLs.updateAndGet(k -> { - k.add(policy); - return k; - }); + badPolicyURLs.add(policy); Object[] source = {policy, pe.getNonlocalizedMessage()}; System.err.println(LocalizedMessage.getNonlocalized (POLICY + ".error.parsing.policy.message", source)); @@ -991,9 +989,7 @@ public class PolicyFile extends java.security.Policy { */ @Override public boolean implies(ProtectionDomain pd, Permission p) { - PolicyInfo pi = policyInfo.get(); - ProtectionDomainCache pdMap = pi.getPdMapping(); - + ProtectionDomainCache pdMap = policyInfo.getPdMapping(); PermissionCollection pc = pdMap.get(pd); if (pc != null) { @@ -1139,9 +1135,7 @@ public class PolicyFile extends java.security.Policy { private Permissions getPermissions(Permissions perms, final CodeSource cs, Principal[] principals) { - PolicyInfo pi = policyInfo.get(); - - for (PolicyEntry entry : pi.policyEntries) { + for (PolicyEntry entry : policyInfo.policyEntries) { addPermissions(perms, cs, principals, entry); } From 07ded2e52d608a51f7241ef6b32016cd00bef397 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Mon, 16 Apr 2018 16:21:58 +0100 Subject: [PATCH 004/102] 8201597: AArch64: Update relocs for CompiledDirectStaticCall Reviewed-by: adinn --- .../cpu/aarch64/nativeInst_aarch64.cpp | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 98672792a32..f61036275ab 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -133,9 +133,29 @@ void NativeMovConstReg::set_data(intptr_t x) { address addr = MacroAssembler::target_addr_for_insn(instruction_address()); *(intptr_t*)addr = x; } else { + // Store x into the instruction stream. MacroAssembler::pd_patch_instruction(instruction_address(), (address)x); ICache::invalidate_range(instruction_address(), instruction_size); } + + // Find and replace the oop/metadata corresponding to this + // instruction in oops section. + CodeBlob* cb = CodeCache::find_blob(instruction_address()); + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + RelocIterator iter(nm, instruction_address(), next_instruction_address()); + while (iter.next()) { + if (iter.type() == relocInfo::oop_type) { + oop* oop_addr = iter.oop_reloc()->oop_addr(); + *oop_addr = cast_to_oop(x); + break; + } else if (iter.type() == relocInfo::metadata_type) { + Metadata** metadata_addr = iter.metadata_reloc()->metadata_addr(); + *metadata_addr = (Metadata*)x; + break; + } + } + } } void NativeMovConstReg::print() { From c76ed565da5e6682ba5f3aa60474b91b9b516d81 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 20 Apr 2018 21:54:36 +0200 Subject: [PATCH 005/102] 8201536: configure fails compiler check due to bad -m32 flag Reviewed-by: erikj --- make/autoconf/flags.m4 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index fef76f8fbba..472e7a638a2 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -233,15 +233,17 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN], # The sysroot flags are needed for configure to be able to run the compilers FLAGS_SETUP_SYSROOT_FLAGS + # For solstudio and xlc, the word size flag is required for correct behavior. + # For clang/gcc, the flag is only strictly required for reduced builds, but + # set it always where possible (x86, sparc and ppc). if test "x$TOOLCHAIN_TYPE" = xxlc; then MACHINE_FLAG="-q${OPENJDK_TARGET_CPU_BITS}" - elif test "x$TOOLCHAIN_TYPE" != xmicrosoft; then - if test "x$OPENJDK_TARGET_CPU" != xaarch64 && - test "x$OPENJDK_TARGET_CPU" != xarm && - test "x$OPENJDK_TARGET_CPU" != xmips && - test "x$OPENJDK_TARGET_CPU" != xmipsel && - test "x$OPENJDK_TARGET_CPU" != xmips64 && - test "x$OPENJDK_TARGET_CPU" != xmips64el; then + elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then + MACHINE_FLAG="-m${OPENJDK_TARGET_CPU_BITS}" + elif test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then + if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86 || + test "x$OPENJDK_TARGET_CPU_ARCH" = xsparc || + test "x$OPENJDK_TARGET_CPU_ARCH" = xppc; then MACHINE_FLAG="-m${OPENJDK_TARGET_CPU_BITS}" fi fi From 4a2ed138029e688d68e24c626b9f76c531cb7502 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 20 Apr 2018 14:30:57 -0700 Subject: [PATCH 006/102] 8201850: [AOT] vm crash when run test compiler/aot/fingerprint/SelfChangedCDS.java Set AOT specific compressed oop shift value before CDS archive load Reviewed-by: iklam, jiangli --- src/hotspot/share/aot/aotLoader.cpp | 51 ++++++++++--------- src/hotspot/share/aot/aotLoader.hpp | 1 + src/hotspot/share/memory/universe.cpp | 1 + .../compiler/aot/fingerprint/CDSDumper.java | 9 +++- .../aot/fingerprint/SelfChangedCDS.java | 23 ++++++++- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/aot/aotLoader.cpp b/src/hotspot/share/aot/aotLoader.cpp index fc18b81cd51..266479d85fc 100644 --- a/src/hotspot/share/aot/aotLoader.cpp +++ b/src/hotspot/share/aot/aotLoader.cpp @@ -183,28 +183,21 @@ void AOTLoader::universe_init() { // Shifts are static values which initialized by 0 until java heap initialization. // AOT libs are loaded before heap initialized so shift values are not set. // It is okay since ObjectAlignmentInBytes flag which defines shifts value is set before AOT libs are loaded. - // Set shifts value based on first AOT library config. + // AOT sets shift values during heap and metaspace initialization. + // Check shifts value to make sure thay did not change. if (UseCompressedOops && AOTLib::narrow_oop_shift_initialized()) { int oop_shift = Universe::narrow_oop_shift(); - if (oop_shift == 0) { - Universe::set_narrow_oop_shift(AOTLib::narrow_oop_shift()); - } else { - FOR_ALL_AOT_LIBRARIES(lib) { - (*lib)->verify_flag(AOTLib::narrow_oop_shift(), oop_shift, "Universe::narrow_oop_shift"); - } + FOR_ALL_AOT_LIBRARIES(lib) { + (*lib)->verify_flag((*lib)->config()->_narrowOopShift, oop_shift, "Universe::narrow_oop_shift"); } if (UseCompressedClassPointers) { // It is set only if UseCompressedOops is set int klass_shift = Universe::narrow_klass_shift(); - if (klass_shift == 0) { - Universe::set_narrow_klass_shift(AOTLib::narrow_klass_shift()); - } else { - FOR_ALL_AOT_LIBRARIES(lib) { - (*lib)->verify_flag(AOTLib::narrow_klass_shift(), klass_shift, "Universe::narrow_klass_shift"); - } + FOR_ALL_AOT_LIBRARIES(lib) { + (*lib)->verify_flag((*lib)->config()->_narrowKlassShift, klass_shift, "Universe::narrow_klass_shift"); } } } - // Create heaps for all the libraries + // Create heaps for all valid libraries FOR_ALL_AOT_LIBRARIES(lib) { if ((*lib)->is_valid()) { AOTCodeHeap* heap = new AOTCodeHeap(*lib); @@ -213,6 +206,9 @@ void AOTLoader::universe_init() { add_heap(heap); CodeCache::add_heap(heap); } + } else { + // Unload invalid libraries + os::dll_unload((*lib)->dl_handle()); } } } @@ -223,20 +219,29 @@ void AOTLoader::universe_init() { } } +// Set shift value for compressed oops and classes based on first AOT library config. +// AOTLoader::universe_init(), which is called later, will check the shift value again to make sure nobody change it. +// This code is not executed during CDS dump because it runs in Interpreter mode and AOT is disabled in this mode. + +void AOTLoader::set_narrow_oop_shift() { + // This method is called from Universe::initialize_heap(). + if (UseAOT && libraries_count() > 0 && + UseCompressedOops && AOTLib::narrow_oop_shift_initialized()) { + if (Universe::narrow_oop_shift() == 0) { + // 0 is valid shift value for small heap but we can safely increase it + // at this point when nobody used it yet. + Universe::set_narrow_oop_shift(AOTLib::narrow_oop_shift()); + } + } +} + void AOTLoader::set_narrow_klass_shift() { - // This method could be called from Metaspace::set_narrow_klass_base_and_shift(). - // In case it is not called (during dump CDS, for example) the corresponding code in - // AOTLoader::universe_init(), which is called later, will set the shift value. + // This method is called from Metaspace::set_narrow_klass_base_and_shift(). if (UseAOT && libraries_count() > 0 && UseCompressedOops && AOTLib::narrow_oop_shift_initialized() && UseCompressedClassPointers) { - int klass_shift = Universe::narrow_klass_shift(); - if (klass_shift == 0) { + if (Universe::narrow_klass_shift() == 0) { Universe::set_narrow_klass_shift(AOTLib::narrow_klass_shift()); - } else { - FOR_ALL_AOT_LIBRARIES(lib) { - (*lib)->verify_flag(AOTLib::narrow_klass_shift(), klass_shift, "Universe::narrow_klass_shift"); - } } } } diff --git a/src/hotspot/share/aot/aotLoader.hpp b/src/hotspot/share/aot/aotLoader.hpp index 87f745d46f0..8a162e57e37 100644 --- a/src/hotspot/share/aot/aotLoader.hpp +++ b/src/hotspot/share/aot/aotLoader.hpp @@ -57,6 +57,7 @@ public: static void initialize() NOT_AOT({ FLAG_SET_ERGO(bool, UseAOT, false); }); static void universe_init() NOT_AOT_RETURN; + static void set_narrow_oop_shift() NOT_AOT_RETURN; static void set_narrow_klass_shift() NOT_AOT_RETURN; static bool contains(address p) NOT_AOT({ return false; }); static void load_for_klass(InstanceKlass* ik, Thread* thread) NOT_AOT_RETURN; diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 6753728d9dd..66da16fabe5 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -786,6 +786,7 @@ jint Universe::initialize_heap() { // Did reserve heap below 32Gb. Can use base == 0; Universe::set_narrow_oop_base(0); } + AOTLoader::set_narrow_oop_shift(); Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java index e789f07e2b7..b0bc027ced5 100644 --- a/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java +++ b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java @@ -31,18 +31,19 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; // Usage: -// java CDSDumper ... +// java CDSDumper ... public class CDSDumper { public static void main(String[] args) throws Exception { String classpath = args[0]; String classlist = args[1]; String archive = args[2]; + String heapsize = args[3]; // Prepare the classlist FileOutputStream fos = new FileOutputStream(classlist); PrintStream ps = new PrintStream(fos); - for (int i=3; i Date: Wed, 18 Apr 2018 11:19:32 +0200 Subject: [PATCH 007/102] 8198756: Lazy allocation of compiler threads Reviewed-by: kvn --- src/hotspot/share/compiler/compileBroker.cpp | 280 +++++++++++++++--- src/hotspot/share/compiler/compileBroker.hpp | 31 +- src/hotspot/share/runtime/globals.hpp | 14 + src/hotspot/share/runtime/thread.cpp | 5 + src/hotspot/share/runtime/thread.hpp | 7 + .../jtreg/runtime/whitebox/WBStackSize.java | 4 +- 6 files changed, 294 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 64a3f60cf81..e72a809fa0c 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -50,6 +50,7 @@ #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/jniHandles.inline.hpp" #include "runtime/os.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" @@ -117,6 +118,17 @@ volatile jint CompileBroker::_should_compile_new_jobs = run_compilation; // The installed compiler(s) AbstractCompiler* CompileBroker::_compilers[2]; +// The maximum numbers of compiler threads to be determined during startup. +int CompileBroker::_c1_count = 0; +int CompileBroker::_c2_count = 0; + +// An array of compiler names as Java String objects +jobject* CompileBroker::_compiler1_objects = NULL; +jobject* CompileBroker::_compiler2_objects = NULL; + +CompileLog** CompileBroker::_compiler1_logs = NULL; +CompileLog** CompileBroker::_compiler2_logs = NULL; + // These counters are used to assign an unique ID to each compilation. volatile jint CompileBroker::_compilation_id = 0; volatile jint CompileBroker::_osr_compilation_id = 0; @@ -286,6 +298,36 @@ CompileTaskWrapper::~CompileTaskWrapper() { } } +/** + * Check if a CompilerThread can be removed and update count if requested. + */ +static bool can_remove(CompilerThread *ct, bool do_it) { + assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here"); + if (!ReduceNumberOfCompilerThreads) return false; + + AbstractCompiler *compiler = ct->compiler(); + int compiler_count = compiler->num_compiler_threads(); + bool c1 = compiler->is_c1(); + + // Keep at least 1 compiler thread of each type. + if (compiler_count < 2) return false; + + // Keep thread alive for at least some time. + if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false; + + // We only allow the last compiler thread of each type to get removed. + jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1) + : CompileBroker::compiler2_object(compiler_count - 1); + if (oopDesc::equals(ct->threadObj(), JNIHandles::resolve_non_null(last_compiler))) { + if (do_it) { + assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent. + compiler->set_num_compiler_threads(compiler_count - 1); + } + return true; + } + return false; +} + /** * Add a CompileTask to a CompileQueue. */ @@ -383,6 +425,11 @@ CompileTask* CompileQueue::get() { // is disabled forever. We use 5 seconds wait time; the exiting of compiler threads // is not critical and we do not want idle compiler threads to wake up too often. MethodCompileQueue_lock->wait(!Mutex::_no_safepoint_check_flag, 5*1000); + + if (UseDynamicNumberOfCompilerThreads && _first == NULL) { + // Still nothing to compile. Give caller a chance to stop this thread. + if (can_remove(CompilerThread::current(), false)) return NULL; + } } if (CompileBroker::is_compilation_disabled_forever()) { @@ -532,8 +579,8 @@ void CompileBroker::compilation_init_phase1(TRAPS) { return; } // Set the interface to the current compiler(s). - int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); - int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); + _c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); + _c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); #if INCLUDE_JVMCI if (EnableJVMCI) { @@ -545,35 +592,35 @@ void CompileBroker::compilation_init_phase1(TRAPS) { if (FLAG_IS_DEFAULT(JVMCIThreads)) { if (BootstrapJVMCI) { // JVMCI will bootstrap so give it more threads - c2_count = MIN2(32, os::active_processor_count()); + _c2_count = MIN2(32, os::active_processor_count()); } } else { - c2_count = JVMCIThreads; + _c2_count = JVMCIThreads; } if (FLAG_IS_DEFAULT(JVMCIHostThreads)) { } else { - c1_count = JVMCIHostThreads; + _c1_count = JVMCIHostThreads; } } } #endif // INCLUDE_JVMCI #ifdef COMPILER1 - if (c1_count > 0) { + if (_c1_count > 0) { _compilers[0] = new Compiler(); } #endif // COMPILER1 #ifdef COMPILER2 if (true JVMCI_ONLY( && !UseJVMCICompiler)) { - if (c2_count > 0) { + if (_c2_count > 0) { _compilers[1] = new C2Compiler(); } } #endif // COMPILER2 // Start the compiler thread(s) and the sweeper thread - init_compiler_sweeper_threads(c1_count, c2_count); + init_compiler_sweeper_threads(); // totalTime performance counter is always created as it is required // by the implementation of java.lang.management.CompilationMBean. { @@ -679,29 +726,38 @@ void CompileBroker::compilation_init_phase2() { _initialized = true; } -JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, - AbstractCompiler* comp, bool compiler_thread, TRAPS) { - JavaThread* thread = NULL; - Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_0); +Handle CompileBroker::create_thread_oop(const char* name, TRAPS) { + Klass* k = SystemDictionary::find(vmSymbols::java_lang_Thread(), Handle(), Handle(), CHECK_NH); + assert(k != NULL, "must be initialized"); InstanceKlass* klass = InstanceKlass::cast(k); - instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_0); - Handle string = java_lang_String::create_from_str(name, CHECK_0); + instanceHandle thread_handle = klass->allocate_instance_handle(CHECK_NH); + Handle string = java_lang_String::create_from_str(name, CHECK_NH); // Initialize thread_oop to put it into the system threadGroup - Handle thread_group (THREAD, Universe::system_thread_group()); + Handle thread_group(THREAD, Universe::system_thread_group()); JavaValue result(T_VOID); - JavaCalls::call_special(&result, thread_oop, + JavaCalls::call_special(&result, thread_handle, klass, vmSymbols::object_initializer_name(), vmSymbols::threadgroup_string_void_signature(), thread_group, string, - CHECK_0); + CHECK_NH); + return thread_handle; +} + + +JavaThread* CompileBroker::make_thread(jobject thread_handle, CompileQueue* queue, + AbstractCompiler* comp, bool compiler_thread, TRAPS) { + JavaThread* thread = NULL; { MutexLocker mu(Threads_lock, THREAD); if (compiler_thread) { - thread = new CompilerThread(queue, counters); + if (!InjectCompilerCreationFailure || comp->num_compiler_threads() == 0) { + CompilerCounters* counters = new CompilerCounters(); + thread = new CompilerThread(queue, counters); + } } else { thread = new CodeCacheSweeperThread(); } @@ -720,13 +776,13 @@ JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, Co if (thread != NULL && thread->osthread() != NULL) { - java_lang_Thread::set_thread(thread_oop(), thread); + java_lang_Thread::set_thread(JNIHandles::resolve_non_null(thread_handle), thread); // Note that this only sets the JavaThread _priority field, which by // definition is limited to Java priorities and not OS priorities. // The os-priority is set in the CompilerThread startup code itself - java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); + java_lang_Thread::set_priority(JNIHandles::resolve_non_null(thread_handle), NearMaxPriority); // Note that we cannot call os::set_priority because it expects Java // priorities and we are *explicitly* using OS priorities so that it's @@ -743,9 +799,9 @@ JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, Co } os::set_native_priority(thread, native_prio); - java_lang_Thread::set_daemon(thread_oop()); + java_lang_Thread::set_daemon(JNIHandles::resolve_non_null(thread_handle)); - thread->set_threadObj(thread_oop()); + thread->set_threadObj(JNIHandles::resolve_non_null(thread_handle)); if (compiler_thread) { thread->as_CompilerThread()->set_compiler(comp); } @@ -756,6 +812,12 @@ JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, Co // First release lock before aborting VM. if (thread == NULL || thread->osthread() == NULL) { + if (UseDynamicNumberOfCompilerThreads && comp->num_compiler_threads() > 0) { + if (thread != NULL) { + thread->smr_delete(); + } + return NULL; + } vm_exit_during_initialization("java.lang.OutOfMemoryError", os::native_thread_creation_failed_msg()); } @@ -767,51 +829,123 @@ JavaThread* CompileBroker::make_thread(const char* name, CompileQueue* queue, Co } -void CompileBroker::init_compiler_sweeper_threads(int c1_compiler_count, int c2_compiler_count) { +void CompileBroker::init_compiler_sweeper_threads() { EXCEPTION_MARK; #if !defined(ZERO) - assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?"); + assert(_c2_count > 0 || _c1_count > 0, "No compilers?"); #endif // !ZERO // Initialize the compilation queue - if (c2_compiler_count > 0) { + if (_c2_count > 0) { const char* name = JVMCI_ONLY(UseJVMCICompiler ? "JVMCI compile queue" :) "C2 compile queue"; _c2_compile_queue = new CompileQueue(name); - _compilers[1]->set_num_compiler_threads(c2_compiler_count); + _compiler2_objects = NEW_C_HEAP_ARRAY(jobject, _c2_count, mtCompiler); + _compiler2_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c2_count, mtCompiler); } - if (c1_compiler_count > 0) { + if (_c1_count > 0) { _c1_compile_queue = new CompileQueue("C1 compile queue"); - _compilers[0]->set_num_compiler_threads(c1_compiler_count); + _compiler1_objects = NEW_C_HEAP_ARRAY(jobject, _c1_count, mtCompiler); + _compiler1_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c1_count, mtCompiler); } - int compiler_count = c1_compiler_count + c2_compiler_count; - char name_buffer[256]; - const bool compiler_thread = true; - for (int i = 0; i < c2_compiler_count; i++) { + + for (int i = 0; i < _c2_count; i++) { // Create a name for our thread. sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i); - CompilerCounters* counters = new CompilerCounters(); - make_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], compiler_thread, CHECK); + jobject thread_handle = JNIHandles::make_global(create_thread_oop(name_buffer, THREAD)); + _compiler2_objects[i] = thread_handle; + _compiler2_logs[i] = NULL; + + if (!UseDynamicNumberOfCompilerThreads || i == 0) { + JavaThread *ct = make_thread(thread_handle, _c2_compile_queue, _compilers[1], /* compiler_thread */ true, CHECK); + assert(ct != NULL, "should have been handled for initial thread"); + _compilers[1]->set_num_compiler_threads(i + 1); + if (TraceCompilerThreads) { + ResourceMark rm; + MutexLocker mu(Threads_lock); + tty->print_cr("Added initial compiler thread %s", ct->get_thread_name()); + } + } } - for (int i = c2_compiler_count; i < compiler_count; i++) { + for (int i = 0; i < _c1_count; i++) { // Create a name for our thread. sprintf(name_buffer, "C1 CompilerThread%d", i); - CompilerCounters* counters = new CompilerCounters(); - // C1 - make_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], compiler_thread, CHECK); + jobject thread_handle = JNIHandles::make_global(create_thread_oop(name_buffer, THREAD)); + _compiler1_objects[i] = thread_handle; + _compiler1_logs[i] = NULL; + + if (!UseDynamicNumberOfCompilerThreads || i == 0) { + JavaThread *ct = make_thread(thread_handle, _c1_compile_queue, _compilers[0], /* compiler_thread */ true, CHECK); + assert(ct != NULL, "should have been handled for initial thread"); + _compilers[0]->set_num_compiler_threads(i + 1); + if (TraceCompilerThreads) { + ResourceMark rm; + MutexLocker mu(Threads_lock); + tty->print_cr("Added initial compiler thread %s", ct->get_thread_name()); + } + } } if (UsePerfData) { - PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK); + PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, _c1_count + _c2_count, CHECK); } if (MethodFlushing) { // Initialize the sweeper thread - make_thread("Sweeper thread", NULL, NULL, NULL, false, CHECK); + jobject thread_handle = JNIHandles::make_local(THREAD, create_thread_oop("Sweeper thread", THREAD)()); + make_thread(thread_handle, NULL, NULL, /* compiler_thread */ false, CHECK); } } +void CompileBroker::possibly_add_compiler_threads() { + EXCEPTION_MARK; + + julong available_memory = os::available_memory(); + // Only do attempt to start additional threads if the lock is free. + if (!CompileThread_lock->try_lock()) return; + + if (_c2_compile_queue != NULL) { + int old_c2_count = _compilers[1]->num_compiler_threads(); + int new_c2_count = MIN3(_c2_count, + _c2_compile_queue->size() / 2, + (int)(available_memory / 200*M)); + + for (int i = old_c2_count; i < new_c2_count; i++) { + JavaThread *ct = make_thread(compiler2_object(i), _c2_compile_queue, _compilers[1], true, CHECK); + if (ct == NULL) break; + _compilers[1]->set_num_compiler_threads(i + 1); + if (TraceCompilerThreads) { + ResourceMark rm; + MutexLocker mu(Threads_lock); + tty->print_cr("Added compiler thread %s (available memory: %dMB)", + ct->get_thread_name(), (int)(available_memory/M)); + } + } + } + + if (_c1_compile_queue != NULL) { + int old_c1_count = _compilers[0]->num_compiler_threads(); + int new_c1_count = MIN3(_c1_count, + _c1_compile_queue->size() / 4, + (int)(available_memory / 100*M)); + + for (int i = old_c1_count; i < new_c1_count; i++) { + JavaThread *ct = make_thread(compiler1_object(i), _c1_compile_queue, _compilers[0], true, CHECK); + if (ct == NULL) break; + _compilers[0]->set_num_compiler_threads(i + 1); + if (TraceCompilerThreads) { + ResourceMark rm; + MutexLocker mu(Threads_lock); + tty->print_cr("Added compiler thread %s (available memory: %dMB)", + ct->get_thread_name(), (int)(available_memory/M)); + } + } + } + + CompileThread_lock->unlock(); +} + /** * Set the methods on the stack as on_stack so that redefine classes doesn't @@ -1546,6 +1680,49 @@ void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerTh } } +/** + * Helper function to create new or reuse old CompileLog. + */ +CompileLog* CompileBroker::get_log(CompilerThread* ct) { + if (!LogCompilation) return NULL; + + AbstractCompiler *compiler = ct->compiler(); + bool c1 = compiler->is_c1(); + jobject* compiler_objects = c1 ? _compiler1_objects : _compiler2_objects; + assert(compiler_objects != NULL, "must be initialized at this point"); + CompileLog** logs = c1 ? _compiler1_logs : _compiler2_logs; + assert(logs != NULL, "must be initialized at this point"); + int count = c1 ? _c1_count : _c2_count; + + // Find Compiler number by its threadObj. + oop compiler_obj = ct->threadObj(); + int compiler_number = 0; + bool found = false; + for (; compiler_number < count; compiler_number++) { + if (oopDesc::equals(JNIHandles::resolve_non_null(compiler_objects[compiler_number]), compiler_obj)) { + found = true; + break; + } + } + assert(found, "Compiler must exist at this point"); + + // Determine pointer for this thread's log. + CompileLog** log_ptr = &logs[compiler_number]; + + // Return old one if it exists. + CompileLog* log = *log_ptr; + if (log != NULL) { + ct->init_log(log); + return log; + } + + // Create a new one and remember it. + init_compiler_thread_log(); + log = ct->log(); + *log_ptr = log; + return log; +} + // ------------------------------------------------------------------ // CompileBroker::compiler_thread_loop // @@ -1568,10 +1745,7 @@ void CompileBroker::compiler_thread_loop() { } // Open a log. - if (LogCompilation) { - init_compiler_thread_log(); - } - CompileLog* log = thread->log(); + CompileLog* log = get_log(thread); if (log != NULL) { log->begin_elem("start_compile_thread name='%s' thread='" UINTX_FORMAT "' process='%d'", thread->name(), @@ -1586,6 +1760,8 @@ void CompileBroker::compiler_thread_loop() { return; } + thread->start_idle_timer(); + // Poll for new compilation tasks as long as the JVM runs. Compilation // should only be disabled if something went wrong while initializing the // compiler runtimes. This, in turn, should not happen. The only known case @@ -1597,9 +1773,24 @@ void CompileBroker::compiler_thread_loop() { CompileTask* task = queue->get(); if (task == NULL) { + if (UseDynamicNumberOfCompilerThreads) { + // Access compiler_count under lock to enforce consistency. + MutexLocker only_one(CompileThread_lock); + if (can_remove(thread, true)) { + if (TraceCompilerThreads) { + tty->print_cr("Removing compiler thread %s after " JLONG_FORMAT " ms idle time", + thread->name(), thread->idle_time_millis()); + } + return; // Stop this thread. + } + } continue; } + if (UseDynamicNumberOfCompilerThreads) { + possibly_add_compiler_threads(); + } + // Give compiler threads an extra quanta. They tend to be bursty and // this helps the compiler to finish up the job. if (CompilerThreadHintNoPreempt) { @@ -1618,6 +1809,7 @@ void CompileBroker::compiler_thread_loop() { // Compile the method. if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { invoke_compiler_on_method(task); + thread->start_idle_timer(); } else { // After compilation is disabled, remove remaining methods from queue method->clear_queued_for_compilation(); diff --git a/src/hotspot/share/compiler/compileBroker.hpp b/src/hotspot/share/compiler/compileBroker.hpp index 8c9aa8221e1..e0a9b4be3a8 100644 --- a/src/hotspot/share/compiler/compileBroker.hpp +++ b/src/hotspot/share/compiler/compileBroker.hpp @@ -161,6 +161,15 @@ class CompileBroker: AllStatic { // The installed compiler(s) static AbstractCompiler* _compilers[2]; + // The maximum numbers of compiler threads to be determined during startup. + static int _c1_count, _c2_count; + + // An array of compiler thread Java objects + static jobject *_compiler1_objects, *_compiler2_objects; + + // An array of compiler logs + static CompileLog **_compiler1_logs, **_compiler2_logs; + // These counters are used for assigning id's to each compilation static volatile jint _compilation_id; static volatile jint _osr_compilation_id; @@ -219,8 +228,11 @@ class CompileBroker: AllStatic { static volatile int _print_compilation_warning; - static JavaThread* make_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, bool compiler_thread, TRAPS); - static void init_compiler_sweeper_threads(int c1_compiler_count, int c2_compiler_count); + static Handle create_thread_oop(const char* name, TRAPS); + static JavaThread* make_thread(jobject thread_oop, CompileQueue* queue, + AbstractCompiler* comp, bool compiler_thread, TRAPS); + static void init_compiler_sweeper_threads(); + static void possibly_add_compiler_threads(); static bool compilation_is_complete (const methodHandle& method, int osr_bci, int comp_level); static bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded); static void preload_classes (const methodHandle& method, TRAPS); @@ -367,6 +379,21 @@ public: // compiler name for debugging static const char* compiler_name(int comp_level); + // Provide access to compiler thread Java objects + static jobject compiler1_object(int idx) { + assert(_compiler1_objects != NULL, "must be initialized"); + assert(idx < _c1_count, "oob"); + return _compiler1_objects[idx]; + } + + static jobject compiler2_object(int idx) { + assert(_compiler2_objects != NULL, "must be initialized"); + assert(idx < _c2_count, "oob"); + return _compiler2_objects[idx]; + } + + static CompileLog* get_log(CompilerThread* ct); + static int get_total_compile_count() { return _total_compile_count; } static int get_total_bailout_count() { return _total_bailout_count; } static int get_total_invalidated_count() { return _total_invalidated_count; } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 147c289b773..bdd3c420bc3 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1486,6 +1486,20 @@ public: range(0, max_jint) \ constraint(CICompilerCountConstraintFunc, AfterErgo) \ \ + product(bool, UseDynamicNumberOfCompilerThreads, true, \ + "Dynamically choose the number of parallel compiler threads") \ + \ + diagnostic(bool, ReduceNumberOfCompilerThreads, true, \ + "Reduce the number of parallel compiler threads when they " \ + "are not used") \ + \ + diagnostic(bool, TraceCompilerThreads, false, \ + "Trace creation and removal of compiler threads") \ + \ + develop(bool, InjectCompilerCreationFailure, false, \ + "Inject thread creation failures for " \ + "UseDynamicNumberOfCompilerThreads") \ + \ product(intx, CompilationPolicyChoice, 0, \ "which compilation policy (0-3)") \ range(0, 3) \ diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index bb407ad7d41..b70e3025039 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -3359,6 +3359,11 @@ CompilerThread::CompilerThread(CompileQueue* queue, #endif } +CompilerThread::~CompilerThread() { + // Delete objects which were allocated on heap. + delete _counters; +} + bool CompilerThread::can_call_java() const { return _compiler != NULL && _compiler->is_jvmci(); } diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index e2b21203df7..38373aec1d8 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -2029,12 +2029,14 @@ class CompilerThread : public JavaThread { BufferBlob* _buffer_blob; AbstractCompiler* _compiler; + TimeStamp _idle_time; public: static CompilerThread* current(); CompilerThread(CompileQueue* queue, CompilerCounters* counters); + ~CompilerThread(); bool is_Compiler_thread() const { return true; } @@ -2064,6 +2066,11 @@ class CompilerThread : public JavaThread { _log = log; } + void start_idle_timer() { _idle_time.update(); } + jlong idle_time_millis() { + return TimeHelper::counter_to_millis(_idle_time.ticks_since_update()); + } + #ifndef PRODUCT private: IdealGraphPrinter *_ideal_graph_printer; diff --git a/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java b/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java index dc5fb024044..f702864e5a7 100644 --- a/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java +++ b/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java @@ -82,7 +82,9 @@ public class WBStackSize { } public static void main(String[] args) { - long configStackSize = wb.getIntxVMFlag("ThreadStackSize") * K; + boolean isCompilerThread = Thread.currentThread().getName().indexOf(" CompilerThread") > 0; + long configStackSize = isCompilerThread ? wb.getIntxVMFlag("CompilerThreadStackSize") * K + : wb.getIntxVMFlag("ThreadStackSize") * K; System.out.println("ThreadStackSize VM option: " + configStackSize); long stackProtectionSize = wb.getIntxVMFlag("StackShadowPages") * wb.getVMPageSize(); From 3e6e4c11edeb9692421ecf0b838088334539413f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 23 Apr 2018 12:16:09 +0200 Subject: [PATCH 008/102] 8202134: Non-PCH build for arm32 fails Reviewed-by: stefank --- src/hotspot/cpu/arm/methodHandles_arm.cpp | 1 + src/hotspot/cpu/arm/relocInfo_arm.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/hotspot/cpu/arm/methodHandles_arm.cpp b/src/hotspot/cpu/arm/methodHandles_arm.cpp index ddee9870228..d4d1bf4abb7 100644 --- a/src/hotspot/cpu/arm/methodHandles_arm.cpp +++ b/src/hotspot/cpu/arm/methodHandles_arm.cpp @@ -35,6 +35,7 @@ #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" #include "runtime/frame.inline.hpp" +#include "utilities/preserveException.hpp" #define __ _masm-> diff --git a/src/hotspot/cpu/arm/relocInfo_arm.cpp b/src/hotspot/cpu/arm/relocInfo_arm.cpp index f1442a341b1..f11c1b8201b 100644 --- a/src/hotspot/cpu/arm/relocInfo_arm.cpp +++ b/src/hotspot/cpu/arm/relocInfo_arm.cpp @@ -29,6 +29,7 @@ #include "nativeInst_arm.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.hpp" +#include "runtime/orderAccess.inline.hpp" #include "runtime/safepoint.hpp" void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { From 0bf983846e2d67cfb7eb94d8d81fe6d1c1397df4 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 23 Apr 2018 13:32:00 +0200 Subject: [PATCH 009/102] 6805750: Improve handling of Attributes.Name Reviewed-by: sherman --- .../classes/java/util/jar/Attributes.java | 132 +++++++++++++----- 1 file changed, 95 insertions(+), 37 deletions(-) diff --git a/src/java.base/share/classes/java/util/jar/Attributes.java b/src/java.base/share/classes/java/util/jar/Attributes.java index 3d966ebb057..016f29e7120 100644 --- a/src/java.base/share/classes/java/util/jar/Attributes.java +++ b/src/java.base/share/classes/java/util/jar/Attributes.java @@ -28,10 +28,10 @@ package java.util.jar; import java.io.DataOutputStream; import java.io.IOException; import java.util.Collection; -import java.util.Comparator; +import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import sun.util.logging.PlatformLogger; @@ -116,7 +116,7 @@ public class Attributes implements Map, Cloneable { * @throws IllegalArgumentException if the attribute name is invalid */ public String getValue(String name) { - return (String)get(new Attributes.Name(name)); + return (String)get(Name.of(name)); } /** @@ -168,7 +168,7 @@ public class Attributes implements Map, Cloneable { * @exception IllegalArgumentException if the attribute name is invalid */ public String putValue(String name, String value) { - return (String)put(new Name(name), value); + return (String)put(Name.of(name), value); } /** @@ -371,7 +371,7 @@ public class Attributes implements Map, Cloneable { */ @SuppressWarnings("deprecation") void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException { - String name = null, value = null; + String name = null, value; byte[] lastline = null; int len; @@ -447,8 +447,21 @@ public class Attributes implements Map, Cloneable { * for more information about valid attribute names and values. */ public static class Name { - private String name; - private int hashCode = -1; + private final String name; + private final int hashCode; + + /** + * Avoid allocation for common Names + */ + private static final Map KNOWN_NAMES; + + static final Name of(String name) { + Name n = KNOWN_NAMES.get(name); + if (n != null) { + return n; + } + return new Name(name); + } /** * Constructs a new attribute name using the given string name. @@ -459,38 +472,33 @@ public class Attributes implements Map, Cloneable { * @exception NullPointerException if the attribute name was null */ public Name(String name) { - if (name == null) { - throw new NullPointerException("name"); - } - if (!isValid(name)) { - throw new IllegalArgumentException(name); - } + this.hashCode = hash(name); this.name = name.intern(); } - private static boolean isValid(String name) { + // Checks the string is valid + private final int hash(String name) { + Objects.requireNonNull(name, "name"); int len = name.length(); if (len > 70 || len == 0) { - return false; + throw new IllegalArgumentException(name); } + // Calculate hash code case insensitively + int h = 0; for (int i = 0; i < len; i++) { - if (!isValid(name.charAt(i))) { - return false; + char c = name.charAt(i); + if (c >= 'a' && c <= 'z') { + // hashcode must be identical for upper and lower case + h = h * 31 + (c - 0x20); + } else if ((c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == '_' || c == '-')) { + h = h * 31 + c; + } else { + throw new IllegalArgumentException(name); } } - return true; - } - - private static boolean isValid(char c) { - return isAlpha(c) || isDigit(c) || c == '_' || c == '-'; - } - - private static boolean isAlpha(char c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); - } - - private static boolean isDigit(char c) { - return c >= '0' && c <= '9'; + return h; } /** @@ -500,9 +508,12 @@ public class Attributes implements Map, Cloneable { * specified attribute object */ public boolean equals(Object o) { + if (this == o) { + return true; + } if (o instanceof Name) { - Comparator c = String.CASE_INSENSITIVE_ORDER; - return c.compare(name, ((Name)o).name) == 0; + Name other = (Name)o; + return other.name.equalsIgnoreCase(name); } else { return false; } @@ -512,9 +523,6 @@ public class Attributes implements Map, Cloneable { * Computes the hash value for this attribute name. */ public int hashCode() { - if (hashCode == -1) { - hashCode = name.toLowerCase(Locale.ROOT).hashCode(); - } return hashCode; } @@ -573,7 +581,7 @@ public class Attributes implements Map, Cloneable { */ public static final Name SEALED = new Name("Sealed"); - /** + /** * {@code Name} object for {@code Extension-List} manifest attribute * used for the extension mechanism that is no longer supported. */ @@ -620,7 +628,7 @@ public class Attributes implements Map, Cloneable { @Deprecated public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id"); - /** + /** * {@code Name} object for {@code Implementation-URL} * manifest attribute. * @@ -654,5 +662,55 @@ public class Attributes implements Map, Cloneable { * @since 9 */ public static final Name MULTI_RELEASE = new Name("Multi-Release"); + + private static void addName(Map names, Name name) { + names.put(name.name, name); + } + + static { + var names = new HashMap(64); + addName(names, MANIFEST_VERSION); + addName(names, SIGNATURE_VERSION); + addName(names, CONTENT_TYPE); + addName(names, CLASS_PATH); + addName(names, MAIN_CLASS); + addName(names, SEALED); + addName(names, EXTENSION_LIST); + addName(names, EXTENSION_NAME); + addName(names, IMPLEMENTATION_TITLE); + addName(names, IMPLEMENTATION_VERSION); + addName(names, IMPLEMENTATION_VENDOR); + addName(names, SPECIFICATION_TITLE); + addName(names, SPECIFICATION_VERSION); + addName(names, SPECIFICATION_VENDOR); + addName(names, MULTI_RELEASE); + + // Common attributes used in MANIFEST.MF et.al; adding these has a + // small footprint cost, but is likely to be quickly paid for by + // reducing allocation when reading and parsing typical manifests + addName(names, new Name("Add-Exports")); + addName(names, new Name("Add-Opens")); + addName(names, new Name("Ant-Version")); + addName(names, new Name("Archiver-Version")); + addName(names, new Name("Build-Jdk")); + addName(names, new Name("Built-By")); + addName(names, new Name("Bnd-LastModified")); + addName(names, new Name("Bundle-Description")); + addName(names, new Name("Bundle-DocURL")); + addName(names, new Name("Bundle-License")); + addName(names, new Name("Bundle-ManifestVersion")); + addName(names, new Name("Bundle-Name")); + addName(names, new Name("Bundle-Vendor")); + addName(names, new Name("Bundle-Version")); + addName(names, new Name("Bundle-SymbolicName")); + addName(names, new Name("Created-By")); + addName(names, new Name("Export-Package")); + addName(names, new Name("Import-Package")); + addName(names, new Name("Name")); + addName(names, new Name("SHA1-Digest")); + addName(names, new Name("X-Compile-Source-JDK")); + addName(names, new Name("X-Compile-Target-JDK")); + KNOWN_NAMES = names; + } } } From 04e986f200ca7170e24f5af1fe1bae7a0e6dadaf Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 23 Apr 2018 11:25:53 +0200 Subject: [PATCH 010/102] 8202081: Introduce CollectedHeap::is_oop() Reviewed-by: eosterlund, rkennke --- src/hotspot/share/gc/shared/collectedHeap.cpp | 16 ++++++++++++++++ src/hotspot/share/gc/shared/collectedHeap.hpp | 2 ++ src/hotspot/share/oops/oop.cpp | 7 +++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index d1383dca253..f4641a2cfcc 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -172,6 +172,22 @@ bool CollectedHeap::request_concurrent_phase(const char* phase) { return false; } +bool CollectedHeap::is_oop(oop object) const { + if (!check_obj_alignment(object)) { + return false; + } + + if (!is_in_reserved(object)) { + return false; + } + + if (is_in_reserved(object->klass_or_null())) { + return false; + } + + return true; +} + // Memory state functions. diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 5e0a224ec8e..3b479e96cf9 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -591,6 +591,8 @@ class CollectedHeap : public CHeapObj { virtual oop pin_object(JavaThread* thread, oop obj); virtual void unpin_object(JavaThread* thread, oop obj); + virtual bool is_oop(oop object) const; + // Non product verification and debugging. #ifndef PRODUCT // Support for PromotionFailureALot. Return true if it's time to cause a diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index bc4333f9980..4ed977cad01 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -122,10 +122,9 @@ unsigned int oopDesc::new_hash(juint seed) { // used only for asserts and guarantees bool oopDesc::is_oop(oop obj, bool ignore_mark_word) { - if (!check_obj_alignment(obj)) return false; - if (!Universe::heap()->is_in_reserved(obj)) return false; - // obj is aligned and accessible in heap - if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false; + if (!Universe::heap()->is_oop(obj)) { + return false; + } // Header verification: the mark is typically non-NULL. If we're // at a safepoint, it must not be null. From 2329ce7e2dd23abe255e871700ecc42ed07b6456 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 23 Apr 2018 16:25:16 +0200 Subject: [PATCH 011/102] 8202073: MetaspaceAllocationTest gtest shall lock during space creation Reviewed-by: coleenp --- src/hotspot/share/memory/metaspace.cpp | 2 ++ .../hotspot/gtest/memory/test_metaspace_allocation.cpp | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index ce867a5ab95..3ffc2926143 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -3378,6 +3378,7 @@ void SpaceManager::track_metaspace_memory_usage() { } MetaWord* SpaceManager::grow_and_allocate(size_t word_size) { + assert_lock_strong(_lock); assert(vs_list()->current_virtual_space() != NULL, "Should have been set"); assert(current_chunk() == NULL || @@ -3553,6 +3554,7 @@ void SpaceManager::deallocate(MetaWord* p, size_t word_size) { // Adds a chunk to the list of chunks in use. void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { + assert_lock_strong(_lock); assert(new_chunk != NULL, "Should not be NULL"); assert(new_chunk->next() == NULL, "Should not be on a list"); diff --git a/test/hotspot/gtest/memory/test_metaspace_allocation.cpp b/test/hotspot/gtest/memory/test_metaspace_allocation.cpp index 446cf8dd67f..993bb6769c3 100644 --- a/test/hotspot/gtest/memory/test_metaspace_allocation.cpp +++ b/test/hotspot/gtest/memory/test_metaspace_allocation.cpp @@ -26,6 +26,7 @@ #include "memory/allocation.inline.hpp" #include "memory/metaspace.hpp" #include "runtime/mutex.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" @@ -104,7 +105,12 @@ protected: // Let every ~10th space be an anonymous one to test different allocation patterns. const Metaspace::MetaspaceType msType = (os::random() % 100 < 10) ? Metaspace::AnonymousMetaspaceType : Metaspace::StandardMetaspaceType; - _spaces[i].space = new ClassLoaderMetaspace(_spaces[i].lock, msType); + { + // Pull lock during space creation, since this is what happens in the VM too + // (see ClassLoaderData::metaspace_non_null(), which we mimick here). + MutexLockerEx ml(_spaces[i].lock, Mutex::_no_safepoint_check_flag); + _spaces[i].space = new ClassLoaderMetaspace(_spaces[i].lock, msType); + } _spaces[i].allocated = 0; ASSERT_TRUE(_spaces[i].space != NULL); } @@ -171,6 +177,7 @@ protected: } else { size = os::random() % 64; } + // Note: In contrast to space creation, no need to lock here. ClassLoaderMetaspace::allocate() will lock itself. MetaWord* const p = _spaces[index].space->allocate(size, mdType); if (p == NULL) { // We very probably did hit the metaspace "until-gc" limit. @@ -196,6 +203,7 @@ protected: force_switch = true; } else { assert(_spaces[index].space != NULL && _spaces[index].allocated > 0, "Sanity"); + // Note: do not lock here. In the "wild" (the VM), we do not so either (see ~ClassLoaderData()). delete _spaces[index].space; _spaces[index].space = NULL; _spaces[index].allocated = 0; From cac6379cc4dcbebed500bedd62f6ea0c78d356cd Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 23 Apr 2018 07:51:46 -0700 Subject: [PATCH 012/102] 8188105: Make -Xshare:auto the default for server VM Reviewed-by: dholmes, lfoltan, acorn, mseledtsov, jiangli --- src/hotspot/share/runtime/arguments.cpp | 12 ----- .../CDSCompressedKPtrs/XShareAuto.java | 54 +++++++++---------- .../CompressedClassPointers.java | 8 ++- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 42bfb0596b3..874c86a018d 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1820,18 +1820,6 @@ jint Arguments::set_ergonomics_flags() { GCConfig::initialize(); -#if COMPILER2_OR_JVMCI - // Shared spaces work fine with other GCs but causes bytecode rewriting - // to be disabled, which hurts interpreter performance and decreases - // server performance. When -server is specified, keep the default off - // unless it is asked for. Future work: either add bytecode rewriting - // at link time, or rewrite bytecodes in non-shared methods. - if (is_server_compilation_mode_vm() && !DumpSharedSpaces && !RequireSharedSpaces && - (FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) { - no_shared_spaces("COMPILER2 default: -Xshare:auto | off, have to manually setup to on."); - } -#endif - #if defined(IA32) // Only server compiler can optimize safepoints well enough. if (!is_server_compilation_mode_vm()) { diff --git a/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/XShareAuto.java b/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/XShareAuto.java index ed742a8f06c..24d712f0b85 100644 --- a/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/XShareAuto.java +++ b/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/XShareAuto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @requires vm.cds * @bug 8005933 - * @summary Test that -Xshare:auto uses CDS when explicitly specified with -server. + * @summary -Xshare:auto is the default when -Xshare is not specified * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -45,34 +45,30 @@ public class XShareAuto { output.shouldContain("Loading classes to share"); output.shouldHaveExitValue(0); - pb = ProcessTools.createJavaProcessBuilder( - "-server", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./XShareAuto.jsa", "-version"); - output = new OutputAnalyzer(pb.start()); - String outputString = output.getOutput(); - // We asked for server but it could be aliased to something else - if (outputString.contains("Server VM") && !outputString.contains("emulated-client")) { - // In server case we don't expect to see sharing flag - output.shouldNotContain("sharing"); + + // We have 2 test cases: + String cases[] = { + "-Xshare:auto", // case [1]: -Xshare:auto is explicitly specified. + "-showversion" // case [2]: -Xshare:auto is not explicitly specified, + // but VM should still use it by default. + }; + + for (String x : cases) { + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./XShareAuto.jsa", + "-Xlog:cds", + x, + "-version"); + output = new OutputAnalyzer(pb.start()); + String outputString = output.getOutput(); + + if (!outputString.contains("Unable to map")) { + // sharing may not be enabled if XShareAuto.jsa cannot be mapped due to + // ASLR. + output.shouldContain("sharing"); + } output.shouldHaveExitValue(0); } - else { - System.out.println("Skipping test - no Server VM available"); - return; - } - - pb = ProcessTools.createJavaProcessBuilder( - "-server", "-Xshare:auto", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./XShareAuto.jsa", "-Xlog:cds", "-version"); - output = new OutputAnalyzer(pb.start()); - try { - output.shouldContain("sharing"); - } catch (RuntimeException e) { - // if sharing failed due to ASLR or similar reasons, - // check whether sharing was attempted at all (UseSharedSpaces) - output.shouldContain("UseSharedSpaces:"); - output.shouldNotContain("Unable to map %s"); - } - output.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java index bd41e30b725..c6f592af01a 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,8 @@ public class CompressedClassPointers { "-XX:SharedBaseAddress=8g", "-Xmx128m", "-Xlog:gc+metaspace=trace", + "-Xshare:off", + "-Xlog:cds=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); @@ -54,6 +56,8 @@ public class CompressedClassPointers { "-XX:CompressedClassSpaceSize=3g", "-Xmx128m", "-Xlog:gc+metaspace=trace", + "-Xshare:off", + "-Xlog:cds=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3"); @@ -66,6 +70,8 @@ public class CompressedClassPointers { "-Xmx30g", "-XX:-UseAOT", // AOT explicitly set klass shift to 3. "-Xlog:gc+metaspace=trace", + "-Xshare:off", + "-Xlog:cds=trace", "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("Narrow klass base: 0x0000000000000000"); From 3649ace8a0c195a8c820f66f703190043ea6ca1f Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Mon, 23 Apr 2018 08:36:41 -0700 Subject: [PATCH 013/102] 8202091: Rename DualStackPlainSocketImpl to PlainSocketImpl [win] Reviewed-by: clanger, chegar --- .../java/net/DualStackPlainSocketImpl.java | 356 ------------- .../classes/java/net/PlainSocketImpl.java | 502 ++++++++++-------- ...ackPlainSocketImpl.c => PlainSocketImpl.c} | 91 ++-- 3 files changed, 332 insertions(+), 617 deletions(-) delete mode 100644 src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java rename src/java.base/windows/native/libnet/{DualStackPlainSocketImpl.c => PlainSocketImpl.c} (84%) diff --git a/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java b/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java deleted file mode 100644 index 13d232638d6..00000000000 --- a/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.net; - -import java.io.IOException; -import java.io.FileDescriptor; -import java.security.AccessController; -import java.security.PrivilegedAction; -import sun.security.action.GetPropertyAction; -import jdk.internal.misc.SharedSecrets; -import jdk.internal.misc.JavaIOFileDescriptorAccess; - -/** - * This class defines the plain SocketImpl. - * When java.net.preferIPv4Stack system property is set to true, it uses - * IPv4-only socket. - * When java.net.preferIPv4Stack is set to false, it handles both IPv4 - * and IPv6 through a single file descriptor. - * - * @author Chris Hegarty - */ - -class DualStackPlainSocketImpl extends AbstractPlainSocketImpl { - - private static final JavaIOFileDescriptorAccess fdAccess = - SharedSecrets.getJavaIOFileDescriptorAccess(); - - private static final boolean preferIPv4Stack = - Boolean.parseBoolean(AccessController.doPrivileged( - new GetPropertyAction("java.net.preferIPv4Stack", "false"))); - - /** - * Empty value of sun.net.useExclusiveBind is treated as 'true'. - */ - private static final boolean useExclusiveBind; - - static { - String exclBindProp = AccessController.doPrivileged( - new GetPropertyAction("sun.net.useExclusiveBind", "")); - useExclusiveBind = exclBindProp.isEmpty() - || Boolean.parseBoolean(exclBindProp); - } - - // emulates SO_REUSEADDR when useExclusiveBind is true - private boolean isReuseAddress; - - public DualStackPlainSocketImpl() { - } - - public DualStackPlainSocketImpl(FileDescriptor fd) { - this.fd = fd; - } - - @Override - void socketCreate(boolean stream) throws IOException { - if (fd == null) - throw new SocketException("Socket closed"); - - int newfd = socket0(stream); - - fdAccess.set(fd, newfd); - } - - @Override - void socketConnect(InetAddress address, int port, int timeout) - throws IOException { - int nativefd = checkAndReturnNativeFD(); - - if (address == null) - throw new NullPointerException("inet address argument is null."); - - if (preferIPv4Stack && !(address instanceof Inet4Address)) - throw new SocketException("Protocol family not supported"); - - int connectResult; - if (timeout <= 0) { - connectResult = connect0(nativefd, address, port); - } else { - configureBlocking(nativefd, false); - try { - connectResult = connect0(nativefd, address, port); - if (connectResult == WOULDBLOCK) { - waitForConnect(nativefd, timeout); - } - } finally { - configureBlocking(nativefd, true); - } - } - /* - * We need to set the local port field. If bind was called - * previous to the connect (by the client) then localport field - * will already be set. - */ - if (localport == 0) - localport = localPort0(nativefd); - } - - @Override - void socketBind(InetAddress address, int port) throws IOException { - int nativefd = checkAndReturnNativeFD(); - - if (address == null) - throw new NullPointerException("inet address argument is null."); - - if (preferIPv4Stack && !(address instanceof Inet4Address)) - throw new SocketException("Protocol family not supported"); - - bind0(nativefd, address, port, useExclusiveBind); - if (port == 0) { - localport = localPort0(nativefd); - } else { - localport = port; - } - - this.address = address; - } - - @Override - void socketListen(int backlog) throws IOException { - int nativefd = checkAndReturnNativeFD(); - - listen0(nativefd, backlog); - } - - @Override - void socketAccept(SocketImpl s) throws IOException { - int nativefd = checkAndReturnNativeFD(); - - if (s == null) - throw new NullPointerException("socket is null"); - - int newfd = -1; - InetSocketAddress[] isaa = new InetSocketAddress[1]; - if (timeout <= 0) { - newfd = accept0(nativefd, isaa); - } else { - configureBlocking(nativefd, false); - try { - waitForNewConnection(nativefd, timeout); - newfd = accept0(nativefd, isaa); - if (newfd != -1) { - configureBlocking(newfd, true); - } - } finally { - configureBlocking(nativefd, true); - } - } - /* Update (SocketImpl)s' fd */ - fdAccess.set(s.fd, newfd); - /* Update socketImpls remote port, address and localport */ - InetSocketAddress isa = isaa[0]; - s.port = isa.getPort(); - s.address = isa.getAddress(); - s.localport = localport; - if (preferIPv4Stack && !(s.address instanceof Inet4Address)) - throw new SocketException("Protocol family not supported"); - } - - @Override - int socketAvailable() throws IOException { - int nativefd = checkAndReturnNativeFD(); - return available0(nativefd); - } - - @Override - void socketClose0(boolean useDeferredClose/*unused*/) throws IOException { - if (fd == null) - throw new SocketException("Socket closed"); - - if (!fd.valid()) - return; - - final int nativefd = fdAccess.get(fd); - fdAccess.set(fd, -1); - close0(nativefd); - } - - @Override - void socketShutdown(int howto) throws IOException { - int nativefd = checkAndReturnNativeFD(); - shutdown0(nativefd, howto); - } - - // Intentional fallthrough after SO_REUSEADDR - @SuppressWarnings("fallthrough") - @Override - void socketSetOption(int opt, boolean on, Object value) - throws SocketException { - - // SO_REUSEPORT is not supported on Windows. - if (opt == SO_REUSEPORT) { - throw new UnsupportedOperationException("unsupported option"); - } - - int nativefd = checkAndReturnNativeFD(); - - if (opt == SO_TIMEOUT) { - if (preferIPv4Stack) { - // Don't enable the socket option on ServerSocket as it's - // meaningless (we don't receive on a ServerSocket). - if (serverSocket == null) { - setSoTimeout0(nativefd, ((Integer)value).intValue()); - } - } // else timeout is implemented through select. - return; - } - - int optionValue = 0; - - switch(opt) { - case SO_REUSEADDR: - if (useExclusiveBind) { - // SO_REUSEADDR emulated when using exclusive bind - isReuseAddress = on; - return; - } - // intentional fallthrough - case TCP_NODELAY: - case SO_OOBINLINE: - case SO_KEEPALIVE: - optionValue = on ? 1 : 0; - break; - case SO_SNDBUF: - case SO_RCVBUF: - case IP_TOS: - optionValue = ((Integer)value).intValue(); - break; - case SO_LINGER: - if (on) { - optionValue = ((Integer)value).intValue(); - } else { - optionValue = -1; - } - break; - default :/* shouldn't get here */ - throw new SocketException("Option not supported"); - } - - setIntOption(nativefd, opt, optionValue); - } - - @Override - int socketGetOption(int opt, Object iaContainerObj) - throws SocketException { - - // SO_REUSEPORT is not supported on Windows. - if (opt == SO_REUSEPORT) { - throw new UnsupportedOperationException("unsupported option"); - } - - int nativefd = checkAndReturnNativeFD(); - - // SO_BINDADDR is not a socket option. - if (opt == SO_BINDADDR) { - localAddress(nativefd, (InetAddressContainer)iaContainerObj); - return 0; // return value doesn't matter. - } - - // SO_REUSEADDR emulated when using exclusive bind - if (opt == SO_REUSEADDR && useExclusiveBind) - return isReuseAddress ? 1 : -1; - - int value = getIntOption(nativefd, opt); - - switch (opt) { - case TCP_NODELAY: - case SO_OOBINLINE: - case SO_KEEPALIVE: - case SO_REUSEADDR: - return (value == 0) ? -1 : 1; - } - return value; - } - - @Override - void socketSendUrgentData(int data) throws IOException { - int nativefd = checkAndReturnNativeFD(); - sendOOB(nativefd, data); - } - - private int checkAndReturnNativeFD() throws SocketException { - if (fd == null || !fd.valid()) - throw new SocketException("Socket closed"); - - return fdAccess.get(fd); - } - - static final int WOULDBLOCK = -2; // Nothing available (non-blocking) - - static { - initIDs(); - } - - /* Native methods */ - - static native void initIDs(); - - static native int socket0(boolean stream) throws IOException; - - static native void bind0(int fd, InetAddress localAddress, int localport, - boolean exclBind) - throws IOException; - - static native int connect0(int fd, InetAddress remote, int remotePort) - throws IOException; - - static native void waitForConnect(int fd, int timeout) throws IOException; - - static native int localPort0(int fd) throws IOException; - - static native void localAddress(int fd, InetAddressContainer in) throws SocketException; - - static native void listen0(int fd, int backlog) throws IOException; - - static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException; - - static native void waitForNewConnection(int fd, int timeout) throws IOException; - - static native int available0(int fd) throws IOException; - - static native void close0(int fd) throws IOException; - - static native void shutdown0(int fd, int howto) throws IOException; - - static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException; - - static native void setSoTimeout0(int fd, int timeout) throws SocketException; - - static native int getIntOption(int fd, int cmd) throws SocketException; - - static native void sendOOB(int fd, int data) throws IOException; - - static native void configureBlocking(int fd, boolean blocking) throws IOException; -} diff --git a/src/java.base/windows/classes/java/net/PlainSocketImpl.java b/src/java.base/windows/classes/java/net/PlainSocketImpl.java index b93190c389f..643411d3769 100644 --- a/src/java.base/windows/classes/java/net/PlainSocketImpl.java +++ b/src/java.base/windows/classes/java/net/PlainSocketImpl.java @@ -24,261 +24,335 @@ */ package java.net; -import java.io.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.security.action.GetPropertyAction; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.JavaIOFileDescriptorAccess; -/* - * This class PlainSocketImpl simply delegates to the appropriate real - * SocketImpl. We do this because PlainSocketImpl is already extended - * by SocksSocketImpl. - *

- * There is one possibility for the real SocketImpl: DualStackPlainSocketImpl. +/** + * On Windows system we simply delegate to native methods. * * @author Chris Hegarty */ class PlainSocketImpl extends AbstractPlainSocketImpl { - private AbstractPlainSocketImpl impl; + + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + private static final boolean preferIPv4Stack = + Boolean.parseBoolean(AccessController.doPrivileged( + new GetPropertyAction("java.net.preferIPv4Stack", "false"))); + + /** + * Empty value of sun.net.useExclusiveBind is treated as 'true'. + */ + private static final boolean useExclusiveBind; + + static { + String exclBindProp = AccessController.doPrivileged( + new GetPropertyAction("sun.net.useExclusiveBind", "")); + useExclusiveBind = exclBindProp.isEmpty() + || Boolean.parseBoolean(exclBindProp); + } + + // emulates SO_REUSEADDR when useExclusiveBind is true + private boolean isReuseAddress; /** * Constructs an empty instance. */ - PlainSocketImpl() { - impl = new DualStackPlainSocketImpl(); + public PlainSocketImpl() { } /** * Constructs an instance with the given file descriptor. */ - PlainSocketImpl(FileDescriptor fd) { - impl = new DualStackPlainSocketImpl(fd); + public PlainSocketImpl(FileDescriptor fd) { + this.fd = fd; } - // Override methods in SocketImpl that access impl's fields. - - protected FileDescriptor getFileDescriptor() { - return impl.getFileDescriptor(); - } - - protected InetAddress getInetAddress() { - return impl.getInetAddress(); - } - - protected int getPort() { - return impl.getPort(); - } - - protected int getLocalPort() { - return impl.getLocalPort(); - } - - void setSocket(Socket soc) { - impl.setSocket(soc); - } - - Socket getSocket() { - return impl.getSocket(); - } - - void setServerSocket(ServerSocket soc) { - impl.setServerSocket(soc); - } - - ServerSocket getServerSocket() { - return impl.getServerSocket(); - } - - public String toString() { - return impl.toString(); - } - - // Override methods in AbstractPlainSocketImpl that access impl's fields. - - protected synchronized void create(boolean stream) throws IOException { - impl.create(stream); - - // set fd to delegate's fd to be compatible with older releases - this.fd = impl.fd; - } - - protected void connect(String host, int port) - throws UnknownHostException, IOException - { - impl.connect(host, port); - } - - protected void connect(InetAddress address, int port) throws IOException { - impl.connect(address, port); - } - - protected void connect(SocketAddress address, int timeout) throws IOException { - impl.connect(address, timeout); - } - - public void setOption(int opt, Object val) throws SocketException { - impl.setOption(opt, val); - } - - public Object getOption(int opt) throws SocketException { - return impl.getOption(opt); - } - - synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { - impl.doConnect(address, port, timeout); - } - - protected synchronized void bind(InetAddress address, int lport) - throws IOException - { - impl.bind(address, lport); - } - - protected synchronized void accept(SocketImpl s) throws IOException { - if (s instanceof PlainSocketImpl) { - // pass in the real impl not the wrapper. - SocketImpl delegate = ((PlainSocketImpl)s).impl; - delegate.address = new InetAddress(); - delegate.fd = new FileDescriptor(); - impl.accept(delegate); - // set fd to delegate's fd to be compatible with older releases - s.fd = delegate.fd; - } else { - impl.accept(s); - } - } - - void setFileDescriptor(FileDescriptor fd) { - impl.setFileDescriptor(fd); - } - - void setAddress(InetAddress address) { - impl.setAddress(address); - } - - void setPort(int port) { - impl.setPort(port); - } - - void setLocalPort(int localPort) { - impl.setLocalPort(localPort); - } - - protected synchronized InputStream getInputStream() throws IOException { - return impl.getInputStream(); - } - - void setInputStream(SocketInputStream in) { - impl.setInputStream(in); - } - - protected synchronized OutputStream getOutputStream() throws IOException { - return impl.getOutputStream(); - } - - protected void close() throws IOException { - try { - impl.close(); - } finally { - // set fd to delegate's fd to be compatible with older releases - this.fd = null; - } - } - - void reset() throws IOException { - try { - impl.reset(); - } finally { - // set fd to delegate's fd to be compatible with older releases - this.fd = null; - } - } - - protected void shutdownInput() throws IOException { - impl.shutdownInput(); - } - - protected void shutdownOutput() throws IOException { - impl.shutdownOutput(); - } - - protected void sendUrgentData(int data) throws IOException { - impl.sendUrgentData(data); - } - - FileDescriptor acquireFD() { - return impl.acquireFD(); - } - - void releaseFD() { - impl.releaseFD(); - } - - boolean isConnectionReset() { - return impl.isConnectionReset(); - } - - void setConnectionReset() { - impl.setConnectionReset(); - } - - public boolean isClosedOrPending() { - return impl.isClosedOrPending(); - } - - public int getTimeout() { - return impl.getTimeout(); - } - - // Override methods in AbstractPlainSocketImpl that need to be implemented. - + @Override void socketCreate(boolean stream) throws IOException { - impl.socketCreate(stream); + if (fd == null) + throw new SocketException("Socket closed"); + + int newfd = socket0(stream); + + fdAccess.set(fd, newfd); } + @Override void socketConnect(InetAddress address, int port, int timeout) throws IOException { - impl.socketConnect(address, port, timeout); + int nativefd = checkAndReturnNativeFD(); + + if (address == null) + throw new NullPointerException("inet address argument is null."); + + if (preferIPv4Stack && !(address instanceof Inet4Address)) + throw new SocketException("Protocol family not supported"); + + int connectResult; + if (timeout <= 0) { + connectResult = connect0(nativefd, address, port); + } else { + configureBlocking(nativefd, false); + try { + connectResult = connect0(nativefd, address, port); + if (connectResult == WOULDBLOCK) { + waitForConnect(nativefd, timeout); + } + } finally { + configureBlocking(nativefd, true); + } + } + /* + * We need to set the local port field. If bind was called + * previous to the connect (by the client) then localport field + * will already be set. + */ + if (localport == 0) + localport = localPort0(nativefd); } - void socketBind(InetAddress address, int port) - throws IOException { - impl.socketBind(address, port); + @Override + void socketBind(InetAddress address, int port) throws IOException { + int nativefd = checkAndReturnNativeFD(); + + if (address == null) + throw new NullPointerException("inet address argument is null."); + + if (preferIPv4Stack && !(address instanceof Inet4Address)) + throw new SocketException("Protocol family not supported"); + + bind0(nativefd, address, port, useExclusiveBind); + if (port == 0) { + localport = localPort0(nativefd); + } else { + localport = port; + } + + this.address = address; } - void socketListen(int count) throws IOException { - impl.socketListen(count); + @Override + void socketListen(int backlog) throws IOException { + int nativefd = checkAndReturnNativeFD(); + + listen0(nativefd, backlog); } + @Override void socketAccept(SocketImpl s) throws IOException { - impl.socketAccept(s); + int nativefd = checkAndReturnNativeFD(); + + if (s == null) + throw new NullPointerException("socket is null"); + + int newfd = -1; + InetSocketAddress[] isaa = new InetSocketAddress[1]; + if (timeout <= 0) { + newfd = accept0(nativefd, isaa); + } else { + configureBlocking(nativefd, false); + try { + waitForNewConnection(nativefd, timeout); + newfd = accept0(nativefd, isaa); + if (newfd != -1) { + configureBlocking(newfd, true); + } + } finally { + configureBlocking(nativefd, true); + } + } + /* Update (SocketImpl)s' fd */ + fdAccess.set(s.fd, newfd); + /* Update socketImpls remote port, address and localport */ + InetSocketAddress isa = isaa[0]; + s.port = isa.getPort(); + s.address = isa.getAddress(); + s.localport = localport; + if (preferIPv4Stack && !(s.address instanceof Inet4Address)) + throw new SocketException("Protocol family not supported"); } + @Override int socketAvailable() throws IOException { - return impl.socketAvailable(); + int nativefd = checkAndReturnNativeFD(); + return available0(nativefd); } - void socketClose0(boolean useDeferredClose) throws IOException { - impl.socketClose0(useDeferredClose); + @Override + void socketClose0(boolean useDeferredClose/*unused*/) throws IOException { + if (fd == null) + throw new SocketException("Socket closed"); + + if (!fd.valid()) + return; + + final int nativefd = fdAccess.get(fd); + fdAccess.set(fd, -1); + close0(nativefd); } + @Override void socketShutdown(int howto) throws IOException { - impl.socketShutdown(howto); + int nativefd = checkAndReturnNativeFD(); + shutdown0(nativefd, howto); } - void socketSetOption(int cmd, boolean on, Object value) + // Intentional fallthrough after SO_REUSEADDR + @SuppressWarnings("fallthrough") + @Override + void socketSetOption(int opt, boolean on, Object value) throws SocketException { - impl.socketSetOption(cmd, on, value); - } - int socketGetOption(int opt, Object iaContainerObj) throws SocketException { - return impl.socketGetOption(opt, iaContainerObj); - } - - void socketSendUrgentData(int data) throws IOException { - impl.socketSendUrgentData(data); - } - - static boolean isReusePortAvailable() { // SO_REUSEPORT is not supported on Windows. - return false; + if (opt == SO_REUSEPORT) { + throw new UnsupportedOperationException("unsupported option"); + } + + int nativefd = checkAndReturnNativeFD(); + + if (opt == SO_TIMEOUT) { + if (preferIPv4Stack) { + // Don't enable the socket option on ServerSocket as it's + // meaningless (we don't receive on a ServerSocket). + if (serverSocket == null) { + setSoTimeout0(nativefd, ((Integer)value).intValue()); + } + } // else timeout is implemented through select. + return; + } + + int optionValue = 0; + + switch(opt) { + case SO_REUSEADDR: + if (useExclusiveBind) { + // SO_REUSEADDR emulated when using exclusive bind + isReuseAddress = on; + return; + } + // intentional fallthrough + case TCP_NODELAY: + case SO_OOBINLINE: + case SO_KEEPALIVE: + optionValue = on ? 1 : 0; + break; + case SO_SNDBUF: + case SO_RCVBUF: + case IP_TOS: + optionValue = ((Integer)value).intValue(); + break; + case SO_LINGER: + if (on) { + optionValue = ((Integer)value).intValue(); + } else { + optionValue = -1; + } + break; + default :/* shouldn't get here */ + throw new SocketException("Option not supported"); + } + + setIntOption(nativefd, opt, optionValue); } + + @Override + int socketGetOption(int opt, Object iaContainerObj) + throws SocketException { + + // SO_REUSEPORT is not supported on Windows. + if (opt == SO_REUSEPORT) { + throw new UnsupportedOperationException("unsupported option"); + } + + int nativefd = checkAndReturnNativeFD(); + + // SO_BINDADDR is not a socket option. + if (opt == SO_BINDADDR) { + localAddress(nativefd, (InetAddressContainer)iaContainerObj); + return 0; // return value doesn't matter. + } + + // SO_REUSEADDR emulated when using exclusive bind + if (opt == SO_REUSEADDR && useExclusiveBind) + return isReuseAddress ? 1 : -1; + + int value = getIntOption(nativefd, opt); + + switch (opt) { + case TCP_NODELAY: + case SO_OOBINLINE: + case SO_KEEPALIVE: + case SO_REUSEADDR: + return (value == 0) ? -1 : 1; + } + return value; + } + + @Override + void socketSendUrgentData(int data) throws IOException { + int nativefd = checkAndReturnNativeFD(); + sendOOB(nativefd, data); + } + + private int checkAndReturnNativeFD() throws SocketException { + if (fd == null || !fd.valid()) + throw new SocketException("Socket closed"); + + return fdAccess.get(fd); + } + + static final int WOULDBLOCK = -2; // Nothing available (non-blocking) + + static { + initIDs(); + } + + /* Native methods */ + + static native void initIDs(); + + static native int socket0(boolean stream) throws IOException; + + static native void bind0(int fd, InetAddress localAddress, int localport, + boolean exclBind) + throws IOException; + + static native int connect0(int fd, InetAddress remote, int remotePort) + throws IOException; + + static native void waitForConnect(int fd, int timeout) throws IOException; + + static native int localPort0(int fd) throws IOException; + + static native void localAddress(int fd, InetAddressContainer in) throws SocketException; + + static native void listen0(int fd, int backlog) throws IOException; + + static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException; + + static native void waitForNewConnection(int fd, int timeout) throws IOException; + + static native int available0(int fd) throws IOException; + + static native void close0(int fd) throws IOException; + + static native void shutdown0(int fd, int howto) throws IOException; + + static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException; + + static native void setSoTimeout0(int fd, int timeout) throws SocketException; + + static native int getIntOption(int fd, int cmd) throws SocketException; + + static native void sendOOB(int fd, int data) throws IOException; + + static native void configureBlocking(int fd, boolean blocking) throws IOException; } diff --git a/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c b/src/java.base/windows/native/libnet/PlainSocketImpl.c similarity index 84% rename from src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c rename to src/java.base/windows/native/libnet/PlainSocketImpl.c index 73c226efff2..29b665a945d 100644 --- a/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c +++ b/src/java.base/windows/native/libnet/PlainSocketImpl.c @@ -24,7 +24,7 @@ */ #include "net_util.h" -#include "java_net_DualStackPlainSocketImpl.h" +#include "java_net_PlainSocketImpl.h" #include "java_net_SocketOptions.h" #define SET_BLOCKING 0 @@ -34,11 +34,11 @@ static jclass isa_class; /* java.net.InetSocketAddress */ static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: initIDs * Signature: ()V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_initIDs (JNIEnv *env, jclass clazz) { jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); @@ -55,13 +55,13 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: socket0 * Signature: (ZZ)I */ -JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0 +JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_socket0 (JNIEnv *env, jclass clazz, jboolean stream) { - int fd, rv, opt=0; + int fd, rv, opt = 0; int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = ipv6_available() ? AF_INET6 : AF_INET; @@ -86,11 +86,11 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: bind0 * Signature: (ILjava/net/InetAddress;I)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0 +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_bind0 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, jboolean exclBind) { @@ -110,11 +110,11 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: connect0 * Signature: (ILjava/net/InetAddress;I)I */ -JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 +JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_connect0 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { SOCKETADDRESS sa; int rv, sa_len = 0; @@ -129,7 +129,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 if (rv == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK) { - return java_net_DualStackPlainSocketImpl_WOULDBLOCK; + return java_net_PlainSocketImpl_WOULDBLOCK; } else if (err == WSAEADDRNOTAVAIL) { JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", "connect: Address is invalid on local machine," @@ -137,17 +137,17 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 } else { NET_ThrowNew(env, err, "connect"); } - return -1; // return value not important. + // return value not important. } return rv; } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: waitForConnect * Signature: (II)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForConnect (JNIEnv *env, jclass clazz, jint fd, jint timeout) { int rv, retry; int optlen = sizeof(rv); @@ -176,7 +176,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect if (rv == 0) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "connect timed out"); - shutdown( fd, SD_BOTH ); + shutdown(fd, SD_BOTH); return; } @@ -197,7 +197,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect * yielding and retrying. As yielding is problematic in heavy * load conditions we attempt up to 3 times to get the error reason. */ - for (retry=0; retry<3; retry++) { + for (retry = 0; retry < 3; retry++) { NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (char*)&rv, &optlen); if (rv) { @@ -219,11 +219,11 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: localPort0 * Signature: (I)I */ -JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0 +JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_localPort0 (JNIEnv *env, jclass clazz, jint fd) { SOCKETADDRESS sa; int len = sizeof(sa); @@ -241,11 +241,11 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: localAddress * Signature: (ILjava/net/InetAddressContainer;)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_localAddress (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) { int port; SOCKETADDRESS sa; @@ -267,13 +267,12 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); } - /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: listen0 * Signature: (II)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0 +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_listen0 (JNIEnv *env, jclass clazz, jint fd, jint backlog) { if (listen(fd, backlog) == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "listen failed"); @@ -281,13 +280,13 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: accept0 * Signature: (I[Ljava/net/InetSocketAddress;)I */ -JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0 +JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_accept0 (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) { - int newfd, port=0; + int newfd, port = 0; jobject isa; jobject ia; SOCKETADDRESS sa; @@ -315,11 +314,11 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: waitForNewConnection * Signature: (II)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForNewConnection (JNIEnv *env, jclass clazz, jint fd, jint timeout) { int rv; @@ -336,11 +335,11 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnecti } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: available0 * Signature: (I)I */ -JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_available0 +JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_available0 (JNIEnv *env, jclass clazz, jint fd) { jint available = -1; @@ -352,33 +351,32 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_available0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: close0 * Signature: (I)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_close0 +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_close0 (JNIEnv *env, jclass clazz, jint fd) { NET_SocketClose(fd); } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: shutdown0 * Signature: (II)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_shutdown0 +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_shutdown0 (JNIEnv *env, jclass clazz, jint fd, jint howto) { shutdown(fd, howto); } - /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: setIntOption * Signature: (III)V */ JNIEXPORT void JNICALL -Java_java_net_DualStackPlainSocketImpl_setIntOption +Java_java_net_PlainSocketImpl_setIntOption (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) { int level = 0, opt = 0; @@ -412,12 +410,12 @@ Java_java_net_DualStackPlainSocketImpl_setIntOption } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: setSoTimeout0 * Signature: (II)V */ JNIEXPORT void JNICALL -Java_java_net_DualStackPlainSocketImpl_setSoTimeout0 +Java_java_net_PlainSocketImpl_setSoTimeout0 (JNIEnv *env, jclass clazz, jint fd, jint timeout) { /* @@ -457,15 +455,15 @@ Java_java_net_DualStackPlainSocketImpl_setSoTimeout0 } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: getIntOption * Signature: (II)I */ -JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption +JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_getIntOption (JNIEnv *env, jclass clazz, jint fd, jint cmd) { int level = 0, opt = 0; - int result=0; + int result = 0; struct linger linger = {0, 0}; char *arg; int arglen; @@ -494,13 +492,12 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption return result; } - /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: sendOOB * Signature: (II)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_sendOOB +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_sendOOB (JNIEnv *env, jclass clazz, jint fd, jint data) { jint n; unsigned char d = (unsigned char) data & 0xff; @@ -512,11 +509,11 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_sendOOB } /* - * Class: java_net_DualStackPlainSocketImpl + * Class: java_net_PlainSocketImpl * Method: configureBlocking * Signature: (IZ)V */ -JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking +JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_configureBlocking (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) { u_long arg; int result; From 70146f48d5eb06d5437820eea643b63fdbaabb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 23 Apr 2018 17:45:05 +0200 Subject: [PATCH 014/102] 8201466: Nashorn: defineProperty setters/getters on prototype object ignored with numeric property names Reviewed-by: sundar, jlaskey --- .../internal/runtime/ScriptObject.java | 15 +++++-- test/nashorn/script/basic/JDK-8201466.js | 44 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 test/nashorn/script/basic/JDK-8201466.js diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java index f46617ea595..ebc1eeb7560 100644 --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java @@ -2969,7 +2969,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { } private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final int callSiteFlags) { - if (getMap().containsArrayKeys()) { + if (hasDefinedArrayProperties()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { @@ -2981,7 +2981,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { } private boolean doesNotHaveCheckArrayKeys(final long longIndex, final double value, final int callSiteFlags) { - if (getMap().containsArrayKeys()) { + if (hasDefinedArrayProperties()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { @@ -2993,7 +2993,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { } private boolean doesNotHaveCheckArrayKeys(final long longIndex, final Object value, final int callSiteFlags) { - if (getMap().containsArrayKeys()) { + if (hasDefinedArrayProperties()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { @@ -3004,6 +3004,15 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { return false; } + private boolean hasDefinedArrayProperties() { + for (ScriptObject obj = this; obj != null; obj = obj.getProto()) { + if (obj.getMap().containsArrayKeys()) { + return true; + } + } + return false; + } + //value agnostic private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) { if (longIndex >= oldLength) { diff --git a/test/nashorn/script/basic/JDK-8201466.js b/test/nashorn/script/basic/JDK-8201466.js new file mode 100644 index 00000000000..b81d44b8d92 --- /dev/null +++ b/test/nashorn/script/basic/JDK-8201466.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8201466: Nashorn: defineProperty setters/getters on prototype object ignored with numeric property names + * + * @test + * @run + */ + +var z = {}, s = null, g = null; + +Object.defineProperty(z,'0', { + get:function(){ g = 2; return 1;}, + set:function(v){ s = v;} +}); + +var x = Object.create(z); +x[0] = 3; + +Assert.assertTrue(x[0] === 1); +Assert.assertTrue(g === 2); +Assert.assertTrue(s === 3); + From ac44a196942f604980c669f5ee93d21eb5eed7e3 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Mon, 23 Apr 2018 09:01:03 -0700 Subject: [PATCH 015/102] 8199193: jshell tool: Add support for preview features Reviewed-by: sundar --- .../jdk/internal/jshell/tool/JShellTool.java | 53 +++++++---- .../jshell/tool/resources/l10n.properties | 1 + .../share/classes/jdk/jshell/TaskFactory.java | 3 +- .../jdk/jshell/ToolEnablePreviewTest.java | 93 +++++++++++++++++++ 4 files changed, 131 insertions(+), 19 deletions(-) create mode 100644 test/langtools/jdk/jshell/ToolEnablePreviewTest.java diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 0bdd37afe6a..79e56566a93 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -209,6 +209,7 @@ public class JShellTool implements MessageHandler { static final EditorSetting BUILT_IN_EDITOR = new EditorSetting(null, false); private boolean debug = false; + private int debugFlags = 0; public boolean testPrompt = false; private Startup startup = null; private boolean isCurrentlyRunningStartup = false; @@ -261,25 +262,28 @@ public class JShellTool implements MessageHandler { MODULE_PATH("--module-path", true), ADD_MODULES("--add-modules", false), ADD_EXPORTS("--add-exports", false), - TO_COMPILER("-C", false, false, true, false), - TO_REMOTE_VM("-R", false, false, false, true),; + ENABLE_PREVIEW("--enable-preview", true), + SOURCE_RELEASE("-source", true, true, true, false, false), // virtual option, generated by --enable-preview + TO_COMPILER("-C", false, false, true, false, false), + TO_REMOTE_VM("-R", false, false, false, true, false),; final String optionFlag; final boolean onlyOne; final boolean passFlag; final boolean toCompiler; final boolean toRemoteVm; + final boolean showOption; private OptionKind(String optionFlag, boolean onlyOne) { - this(optionFlag, onlyOne, true, true, true); + this(optionFlag, onlyOne, true, true, true, true); } - private OptionKind(String optionFlag, boolean onlyOne, boolean passFlag, - boolean toCompiler, boolean toRemoteVm) { + private OptionKind(String optionFlag, boolean onlyOne, boolean passFlag, boolean toCompiler, boolean toRemoteVm, boolean showOption) { this.optionFlag = optionFlag; this.onlyOne = onlyOne; this.passFlag = passFlag; this.toCompiler = toCompiler; this.toRemoteVm = toRemoteVm; + this.showOption= showOption; } } @@ -314,8 +318,8 @@ public class JShellTool implements MessageHandler { return selectOptions(e -> e.getKey().toCompiler); } - String[] commonOptions() { - return selectOptions(e -> e.getKey().passFlag); + String[] shownOptions() { + return selectOptions(e -> e.getKey().showOption); } void addAll(OptionKind kind, Collection vals) { @@ -348,6 +352,7 @@ public class JShellTool implements MessageHandler { private final OptionSpec argModulePath = parser.accepts("module-path").withRequiredArg(); private final OptionSpec argAddModules = parser.accepts("add-modules").withRequiredArg(); private final OptionSpec argAddExports = parser.accepts("add-exports").withRequiredArg(); + private final OptionSpecBuilder argEnablePreview = parser.accepts("enable-preview"); private final NonOptionArgumentSpec argNonOptions = parser.nonOptions(); private Options opts = new Options(); @@ -449,6 +454,13 @@ public class JShellTool implements MessageHandler { .map(mp -> mp.contains("=") ? mp : mp + "=ALL-UNNAMED") .collect(toList()) ); + if (options.has(argEnablePreview)) { + opts.addAll(OptionKind.ENABLE_PREVIEW, List.of( + OptionKind.ENABLE_PREVIEW.optionFlag)); + opts.addAll(OptionKind.SOURCE_RELEASE, List.of( + OptionKind.SOURCE_RELEASE.optionFlag, + System.getProperty("java.specification.version"))); + } if (failed) { exitCode = 1; @@ -1062,6 +1074,7 @@ public class JShellTool implements MessageHandler { builder.executionEngine(executionControlSpec); } state = builder.build(); + InternalDebugControl.setDebugFlags(state, debugFlags); shutdownSubscription = state.onShutdown((JShell deadState) -> { if (deadState == state) { hardmsg("jshell.msg.terminated"); @@ -2234,11 +2247,10 @@ public class JShellTool implements MessageHandler { InternalDebugControl.setDebugFlags(state, debug ? DBG_GEN : 0); fluff("Debugging %s", debug ? "on" : "off"); } else { - int flags = 0; for (char ch : arg.toCharArray()) { switch (ch) { case '0': - flags = 0; + debugFlags = 0; debug = false; fluff("Debugging off"); break; @@ -2247,36 +2259,41 @@ public class JShellTool implements MessageHandler { fluff("REPL tool debugging on"); break; case 'g': - flags |= DBG_GEN; + debugFlags |= DBG_GEN; fluff("General debugging on"); break; case 'f': - flags |= DBG_FMGR; + debugFlags |= DBG_FMGR; fluff("File manager debugging on"); break; case 'c': - flags |= DBG_COMPA; + debugFlags |= DBG_COMPA; fluff("Completion analysis debugging on"); break; case 'd': - flags |= DBG_DEP; + debugFlags |= DBG_DEP; fluff("Dependency debugging on"); break; case 'e': - flags |= DBG_EVNT; + debugFlags |= DBG_EVNT; fluff("Event debugging on"); break; case 'w': - flags |= DBG_WRAP; + debugFlags |= DBG_WRAP; fluff("Wrap debugging on"); break; + case 'b': + cmdout.printf("RemoteVM Options: %s\nCompiler options: %s\n", + Arrays.toString(options.remoteVmOptions()), + Arrays.toString(options.compilerOptions())); + break; default: error("Unknown debugging option: %c", ch); - fluff("Use: 0 r g f c d e w"); + fluff("Use: 0 r g f c d e w b"); return false; } } - InternalDebugControl.setDebugFlags(state, flags); + InternalDebugControl.setDebugFlags(state, debugFlags); } return true; } @@ -3112,7 +3129,7 @@ public class JShellTool implements MessageHandler { if (rawargs.trim().isEmpty()) { // No arguments, display current settings (as option flags) StringBuilder sb = new StringBuilder(); - for (String a : options.commonOptions()) { + for (String a : options.shownOptions()) { sb.append( a.startsWith("-") ? sb.length() > 0 diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index 0bc471c9630..fb56582e996 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -205,6 +205,7 @@ where possible options include:\n\ \ --add-modules (,)*\n\ \ Specify modules to resolve, or all modules on the\n\ \ module path if is ALL-MODULE-PATHs\n\ +\ --enable-preview Allow code to depend on preview features of this release\n\ \ --startup One run replacement for the startup definitions\n\ \ --no-startup Do not run the startup definitions\n\ \ --feedback Specify the initial feedback mode. The mode may be\n\ diff --git a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index 18f9eb300a8..eb55f007a27 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -82,7 +82,6 @@ import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.comp.Resolve; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; -import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -91,6 +90,7 @@ import com.sun.tools.javac.util.Context.Factory; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler; import com.sun.tools.javac.util.Names; +import static jdk.internal.jshell.debug.InternalDebugControl.DBG_FMGR; import jdk.jshell.Snippet.Status; /** @@ -202,6 +202,7 @@ class TaskFactory { .map(in -> sh.sourceToFileObject(fileManager, in)) .collect(Collectors.toList()); DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + state.debug(DBG_FMGR, "Task (%s %s) Options: %s\n", this, compilationUnits, allOptions); return javacTaskPool.getTask(null, fileManager, diagnostics, allOptions, null, compilationUnits, task -> { JavacTaskImpl jti = (JavacTaskImpl) task; diff --git a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java new file mode 100644 index 00000000000..e61eb0b537e --- /dev/null +++ b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8199193 + * @summary Tests for the --enable-preview option + * @run testng ToolEnablePreviewTest + */ + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +public class ToolEnablePreviewTest extends ReplToolTesting { + + @Test + public void testOptionDebug() { + String release = System.getProperty("java.specification.version"); + test( + (a) -> assertCommand(a, "/debug b", + "RemoteVM Options: []\n" + + "Compiler options: []"), + (a) -> assertCommand(a, "/env --enable-preview", + "| Setting new options and restoring state."), + (a) -> assertCommandCheckOutput(a, "/debug b", s -> { + assertTrue(s.contains("RemoteVM Options: [--enable-preview]")); + assertTrue(s.contains("Compiler options: [-source, " + release + ", --enable-preview]") + || s.contains("Compiler options: [--enable-preview, -source, " + release + "]"), + "\nExpected -- " + "Compiler options: [-source, " + release + ", --enable-preview]" + + "\nOr -- " + "Compiler options: [--enable-preview, -source, " + release + "]" + + "\nBut got -- " + s); + }) + ); + } + + @Test + public void testCommandLineFlag() { + String release = System.getProperty("java.specification.version"); + test(new String[] {"--enable-preview"}, + (a) -> assertCommandCheckOutput(a, "/debug b", s -> { + assertTrue(s.contains("RemoteVM Options: [--enable-preview]")); + assertTrue(s.contains("Compiler options: [-source, " + release + ", --enable-preview]") + || s.contains("Compiler options: [--enable-preview, -source, " + release + "]"), + "\nExpected -- " + "Compiler options: [-source, " + release + ", --enable-preview]" + + "\nOr -- " + "Compiler options: [--enable-preview, -source, " + release + "]" + + "\nBut got -- " + s); + }) + ); + } + + @Test + public void testCompilerTestFlagEnv() { + test(new String[] {"-C", "-XDforcePreview"}, + (a) -> assertCommandOutputContains(a, "Function f = i -> i + i", + "Error", "preview feature"), + (a) -> assertCommand(a, "/env --enable-preview", + "| Setting new options and restoring state."), + (a) -> assertCommandOutputContains(a, "Function f = i -> i + i", + "f ==> ") + ); + } + + @Test + public void testCompilerTestFlag() { + test(new String[] {"-C", "-XDforcePreview", "--enable-preview"}, + (a) -> assertCommandOutputContains(a, "Function f = i -> i + i", + "f ==> "), + (a) -> assertCommandOutputContains(a, "f.apply(2)", "==> 4") + ); + } + +} From 60723b7e3d971ad81d3a01ede2ef545f68bfd026 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 23 Apr 2018 10:59:39 -0500 Subject: [PATCH 016/102] 8081519: Split globals.hpp to factor out the Flag class Factored out Flag out go globals, renamed to JVMFlag Reviewed-by: coleenp, dholmes, kvn --- .../cpu/aarch64/methodHandles_aarch64.cpp | 1 + .../cpu/sparc/macroAssembler_sparc.cpp | 1 + src/hotspot/cpu/sparc/methodHandles_sparc.cpp | 1 + src/hotspot/cpu/x86/macroAssembler_x86.cpp | 1 + src/hotspot/cpu/x86/methodHandles_x86.cpp | 1 + src/hotspot/share/code/dependencies.cpp | 1 + src/hotspot/share/code/nmethod.cpp | 1 + src/hotspot/share/code/relocInfo.cpp | 3 +- .../gc/cms/concurrentMarkSweepGeneration.cpp | 1 + ...aintsCMS.cpp => jvmFlagConstraintsCMS.cpp} | 88 +- ...aintsCMS.hpp => jvmFlagConstraintsCMS.hpp} | 26 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 + ...traintsG1.cpp => jvmFlagConstraintsG1.cpp} | 64 +- ...traintsG1.hpp => jvmFlagConstraintsG1.hpp} | 18 +- ...lel.cpp => jvmFlagConstraintsParallel.cpp} | 20 +- ...lel.hpp => jvmFlagConstraintsParallel.hpp} | 6 +- src/hotspot/share/gc/parallel/psMarkSweep.cpp | 1 + .../shared/commandLineFlagConstraintsGC.hpp | 73 - .../share/gc/shared/genCollectedHeap.cpp | 1 + ...traintsGC.cpp => jvmFlagConstraintsGC.cpp} | 202 +-- .../share/gc/shared/jvmFlagConstraintsGC.hpp | 73 + src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 3 +- .../share/jvmci/jvmciCompilerToVMInit.cpp | 5 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 23 +- src/hotspot/share/memory/universe.cpp | 5 +- src/hotspot/share/oops/klassVtable.cpp | 1 + src/hotspot/share/precompiled/precompiled.hpp | 11 + src/hotspot/share/prims/whitebox.cpp | 57 +- src/hotspot/share/runtime/arguments.cpp | 236 +-- src/hotspot/share/runtime/arguments.hpp | 7 +- .../runtime/commandLineFlagConstraintList.hpp | 101 -- .../commandLineFlagConstraintsCompiler.hpp | 75 - .../share/runtime/flags/flagSetting.hpp | 71 + src/hotspot/share/runtime/flags/jvmFlag.cpp | 1506 +++++++++++++++++ src/hotspot/share/runtime/flags/jvmFlag.hpp | 283 ++++ .../jvmFlagConstraintList.cpp} | 184 +- .../runtime/flags/jvmFlagConstraintList.hpp | 101 ++ .../jvmFlagConstraintsCompiler.cpp} | 133 +- .../flags/jvmFlagConstraintsCompiler.hpp | 74 + .../jvmFlagConstraintsRuntime.cpp} | 57 +- .../jvmFlagConstraintsRuntime.hpp} | 25 +- .../jvmFlagRangeList.cpp} | 143 +- .../jvmFlagRangeList.hpp} | 40 +- .../jvmFlagWriteableList.cpp} | 62 +- .../jvmFlagWriteableList.hpp} | 23 +- src/hotspot/share/runtime/globals.cpp | 1476 +--------------- src/hotspot/share/runtime/globals.hpp | 347 +--- src/hotspot/share/runtime/globals_ext.hpp | 20 +- .../share/runtime/globals_extension.hpp | 55 +- src/hotspot/share/runtime/handshake.hpp | 1 + src/hotspot/share/runtime/init.cpp | 4 +- src/hotspot/share/runtime/java.cpp | 1 + src/hotspot/share/runtime/mutexLocker.hpp | 1 + src/hotspot/share/runtime/thread.cpp | 13 +- src/hotspot/share/runtime/vmStructs.cpp | 31 +- src/hotspot/share/services/attachListener.cpp | 9 +- .../share/services/diagnosticCommand.cpp | 10 +- src/hotspot/share/services/dtraceAttacher.cpp | 7 +- src/hotspot/share/services/management.cpp | 41 +- src/hotspot/share/services/writeableFlags.cpp | 119 +- src/hotspot/share/services/writeableFlags.hpp | 43 +- src/hotspot/share/utilities/debug.cpp | 1 + .../share/utilities/globalDefinitions.hpp | 7 + .../classes/sun/jvm/hotspot/runtime/VM.java | 6 +- .../gtest/gc/shared/test_collectorPolicy.cpp | 3 +- test/hotspot/gtest/runtime/test_globals.cpp | 21 +- 66 files changed, 3060 insertions(+), 2966 deletions(-) rename src/hotspot/share/gc/cms/{commandLineFlagConstraintsCMS.cpp => jvmFlagConstraintsCMS.cpp} (78%) rename src/hotspot/share/gc/cms/{commandLineFlagConstraintsCMS.hpp => jvmFlagConstraintsCMS.hpp} (60%) rename src/hotspot/share/gc/g1/{commandLineFlagConstraintsG1.cpp => jvmFlagConstraintsG1.cpp} (76%) rename src/hotspot/share/gc/g1/{commandLineFlagConstraintsG1.hpp => jvmFlagConstraintsG1.hpp} (67%) rename src/hotspot/share/gc/parallel/{commandLineFlagConstraintsParallel.cpp => jvmFlagConstraintsParallel.cpp} (82%) rename src/hotspot/share/gc/parallel/{commandLineFlagConstraintsParallel.hpp => jvmFlagConstraintsParallel.hpp} (84%) delete mode 100644 src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp rename src/hotspot/share/gc/shared/{commandLineFlagConstraintsGC.cpp => jvmFlagConstraintsGC.cpp} (71%) create mode 100644 src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp delete mode 100644 src/hotspot/share/runtime/commandLineFlagConstraintList.hpp delete mode 100644 src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp create mode 100644 src/hotspot/share/runtime/flags/flagSetting.hpp create mode 100644 src/hotspot/share/runtime/flags/jvmFlag.cpp create mode 100644 src/hotspot/share/runtime/flags/jvmFlag.hpp rename src/hotspot/share/runtime/{commandLineFlagConstraintList.cpp => flags/jvmFlagConstraintList.cpp} (58%) create mode 100644 src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp rename src/hotspot/share/runtime/{commandLineFlagConstraintsCompiler.cpp => flags/jvmFlagConstraintsCompiler.cpp} (80%) create mode 100644 src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp rename src/hotspot/share/runtime/{commandLineFlagConstraintsRuntime.cpp => flags/jvmFlagConstraintsRuntime.cpp} (77%) rename src/hotspot/share/runtime/{commandLineFlagConstraintsRuntime.hpp => flags/jvmFlagConstraintsRuntime.hpp} (60%) rename src/hotspot/share/runtime/{commandLineFlagRangeList.cpp => flags/jvmFlagRangeList.cpp} (75%) rename src/hotspot/share/runtime/{commandLineFlagRangeList.hpp => flags/jvmFlagRangeList.hpp} (56%) rename src/hotspot/share/runtime/{commandLineFlagWriteableList.cpp => flags/jvmFlagWriteableList.cpp} (76%) rename src/hotspot/share/runtime/{commandLineFlagWriteableList.hpp => flags/jvmFlagWriteableList.hpp} (70%) diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index e717c1e7e96..8ae90a5f2c3 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -30,6 +30,7 @@ #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" #include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #define __ _masm-> diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp index b4a3052a998..f2e1c901b02 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp @@ -35,6 +35,7 @@ #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/objectMonitor.hpp" diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp index 6076f7ab053..f84ba5d0021 100644 --- a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp +++ b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp @@ -31,6 +31,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 43265c8acb2..15181a5d39e 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -37,6 +37,7 @@ #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index e38515a6e7a..dc53107c735 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -31,6 +31,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 03c0ec89318..1c97270a030 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -35,6 +35,7 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c6e4f9e0ad5..65fefb0788d 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -47,6 +47,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 16e2ab8d849..94fb1886b68 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "code/relocInfo.hpp" #include "memory/resourceArea.hpp" #include "oops/compressedOops.inline.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/copy.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp index a4d4c2facf6..8efe5dde48b 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp @@ -68,6 +68,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp similarity index 78% rename from src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp rename to src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp index 367f4e49e82..777ed6ce13d 100644 --- a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp +++ b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp @@ -23,52 +23,52 @@ */ #include "precompiled.hpp" -#include "gc/cms/commandLineFlagConstraintsCMS.hpp" +#include "gc/cms/jvmFlagConstraintsCMS.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/commandLineFlagConstraintsGC.hpp" +#include "gc/shared/jvmFlagConstraintsGC.hpp" #include "memory/universe.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "utilities/globalDefinitions.hpp" -static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { +static JVMFlag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { // CMSWorkQueueDrainThreshold is verified to be less than max_juint if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { CommandLineError::print(verbose, "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" UINTX_FORMAT ") is too large\n", threads, threshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) { +JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) { // To avoid overflow at ParScanClosure::do_oop_work. if (UseConcMarkSweepGC && (value > (max_jint / 10))) { CommandLineError::print(verbose, "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for CMS GC\n", value, (max_jint / 10)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose); } -Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) { CommandLineError::print(verbose, "ParGCStridesPerThread (" UINTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", value, ((uintx)max_jint / (uintx)ParallelGCThreads)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { +JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { if (UseConcMarkSweepGC) { // ParGCCardsPerStrideChunk should be compared with card table size. size_t heap_size = Universe::heap()->reserved_region().word_size(); @@ -80,7 +80,7 @@ Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and " "must be less than or equal to card table size (" SIZE_FORMAT ")\n", value, card_table_size); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread) @@ -93,14 +93,14 @@ Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", value, ergo_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; if (UseConcMarkSweepGC) { if (value > CMSOldPLABMax) { @@ -108,15 +108,15 @@ Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { "CMSOldPLABMin (" SIZE_FORMAT ") must be " "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", value, CMSOldPLABMax); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); } return status; } -Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; if (UseConcMarkSweepGC) { status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); @@ -124,7 +124,7 @@ Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { return status; } -static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { +static JVMFlag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { if (UseConcMarkSweepGC) { ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen(); const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size(); @@ -134,17 +134,17 @@ static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, "less than or equal to ergonomic maximum (" SIZE_FORMAT ") " "which is based on the maximum size of the old generation of the Java heap\n", name, value, ergo_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { - Flag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); +JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); - if (status == Flag::SUCCESS && UseConcMarkSweepGC) { + if (status == JVMFlag::SUCCESS && UseConcMarkSweepGC) { // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size() // to be aligned to CardTable::card_size * BitsPerWord. // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize' @@ -154,40 +154,40 @@ Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { "CMSRescanMultiple (" SIZE_FORMAT ") must be " "a multiple of " SIZE_FORMAT "\n", value, HeapWordSize); - status = Flag::VIOLATES_CONSTRAINT; + status = JVMFlag::VIOLATES_CONSTRAINT; } } return status; } -Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose); } -Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { CommandLineError::print(verbose, "CMSPrecleanDenominator (" UINTX_FORMAT ") must be " "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n", value, CMSPrecleanNumerator); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) { CommandLineError::print(verbose, "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n", value, CMSPrecleanDenominator); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC) { size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity(); if (value > max_uintx - max_capacity) { @@ -195,20 +195,20 @@ Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { "CMSSamplingGrain (" UINTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n", value, max_uintx - max_capacity); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC) { return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose); } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { // Skip for current default value. if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) { // CMSBitMapYieldQuantum should be compared with mark bitmap size. @@ -221,18 +221,18 @@ Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { "be less than or equal to bitmap size (" SIZE_FORMAT ") " "whose size corresponds to the size of old generation of the Java heap\n", value, bitmap_size); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { +JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { if (value == 0) { CommandLineError::print(verbose, "OldPLABSize (" SIZE_FORMAT ") must be greater than 0", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // For CMS, OldPLABSize is the number of free blocks of a given size that are used when // replenishing the local per-worker free list caches. diff --git a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp similarity index 60% rename from src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp rename to src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp index c147e92de99..eabb9fc3933 100644 --- a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp +++ b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp @@ -29,20 +29,20 @@ #include "utilities/globalDefinitions.hpp" // CMS Flag Constraints -Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); -Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); -Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); -Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); -Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); -Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); -Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); -Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); -Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); -Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); -Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); +JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); +JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); +JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); // CMS Subconstraints -Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose); -Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose); +JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose); +JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose); #endif // SHARE_GC_CMS_COMMANDLINEFLAGCONSTRAINTSCMS_HPP diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 33cee250b01..662d730018e 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -84,6 +84,7 @@ #include "oops/oop.inline.hpp" #include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/orderAccess.inline.hpp" diff --git a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp similarity index 76% rename from src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp rename to src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp index eed1c456c01..43de961a1f6 100644 --- a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp @@ -24,12 +24,12 @@ #include "precompiled.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "utilities/globalDefinitions.hpp" -Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1RSetRegionEntries=0 means will be set ergonomically. // Minimum value is 1. @@ -38,14 +38,14 @@ Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { "G1RSetRegionEntries (" INTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. // Minimum value is 1. @@ -54,14 +54,14 @@ Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1HeapRegionSize=0 means will be set ergonomically. if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { @@ -69,53 +69,53 @@ Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { "G1HeapRegionSize (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic heap region minimum size\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; if (value > G1MaxNewSizePercent) { CommandLineError::print(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n", value, G1MaxNewSizePercent); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; if (value < G1NewSizePercent) { CommandLineError::print(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n", value, G1NewSizePercent); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { +JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { CommandLineError::print(verbose, "MaxGCPauseMillis (" UINTX_FORMAT ") must be " "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n", value, GCPauseIntervalMillis); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { +JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC) { if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { if (value < 1) { @@ -123,14 +123,14 @@ Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { CommandLineError::print(verbose, "GCPauseIntervalMillis cannot be set " "without setting MaxGCPauseMillis\n"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value <= MaxGCPauseMillis) { @@ -138,15 +138,15 @@ Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n", value, MaxGCPauseMillis); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { +JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { #ifdef _LP64 // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length // when the value to be assigned exceeds uint range. @@ -156,10 +156,10 @@ Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { CommandLineError::print(verbose, "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif // _LP64 - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } size_t MaxSizeForHeapAlignmentG1() { diff --git a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp similarity index 67% rename from src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp rename to src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp index a81bd4254e1..29a98038296 100644 --- a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp @@ -29,17 +29,17 @@ #include "utilities/globalDefinitions.hpp" // G1 Flag Constraints -Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); -Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); -Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); -Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); -Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); +JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); +JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); +JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); +JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); // G1 Subconstraints -Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose); -Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose); -Flag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose); -Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose); +JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose); +JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose); +JVMFlag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose); +JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose); size_t MaxSizeForHeapAlignmentG1(); diff --git a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp similarity index 82% rename from src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp rename to src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp index 54742369c1a..ab95428b26e 100644 --- a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp +++ b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp @@ -23,11 +23,11 @@ */ #include "precompiled.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" -Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { +JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. // So can't exceed with "max_jint" @@ -36,24 +36,24 @@ Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for Parallel GC\n", value, max_jint); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { +JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // InitialTenuringThreshold is only used for ParallelGC. if (UseParallelGC && (value > MaxTenuringThreshold)) { CommandLineError::print(verbose, "InitialTenuringThreshold (" UINTX_FORMAT ") must be " "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", value, MaxTenuringThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { +JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // As only ParallelGC uses InitialTenuringThreshold, // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. if (UseParallelGC && (value < InitialTenuringThreshold)) { @@ -61,8 +61,8 @@ Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose "MaxTenuringThreshold (" UINTX_FORMAT ") must be " "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", value, InitialTenuringThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp similarity index 84% rename from src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp rename to src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp index caa82209035..b945d8ea3bf 100644 --- a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp +++ b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp @@ -29,8 +29,8 @@ #include "utilities/globalDefinitions.hpp" // Parallel Subconstraints -Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose); -Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); -Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); +JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose); +JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); +JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); #endif // SHARE_GC_PARALLEL_COMMANDLINEFLAGCONSTRAINTSPARALLEL_HPP diff --git a/src/hotspot/share/gc/parallel/psMarkSweep.cpp b/src/hotspot/share/gc/parallel/psMarkSweep.cpp index b7f2770f5f3..48456123347 100644 --- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp +++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp @@ -51,6 +51,7 @@ #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/vmThread.hpp" diff --git a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp deleted file mode 100644 index dcfaf529c97..00000000000 --- a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP -#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc/cms/commandLineFlagConstraintsCMS.hpp" -#include "gc/g1/commandLineFlagConstraintsG1.hpp" -#include "gc/parallel/commandLineFlagConstraintsParallel.hpp" -#endif - -/* - * Here we have GC arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); -Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); -Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); -Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); -Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); - -Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); -Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); -Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); -Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); -Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); -Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose); -Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); -Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); -Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); - -// Internal -Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); - -#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index 30754c90a83..b14db143052 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -53,6 +53,7 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp similarity index 71% rename from src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp rename to src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 14491c91645..4378da92890 100644 --- a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -25,11 +25,11 @@ #include "precompiled.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectorPolicy.hpp" -#include "gc/shared/commandLineFlagConstraintsGC.hpp" +#include "gc/shared/jvmFlagConstraintsGC.hpp" #include "gc/shared/plab.hpp" #include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/thread.inline.hpp" @@ -37,9 +37,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS -#include "gc/cms/commandLineFlagConstraintsCMS.hpp" -#include "gc/g1/commandLineFlagConstraintsG1.hpp" -#include "gc/parallel/commandLineFlagConstraintsParallel.hpp" +#include "gc/cms/jvmFlagConstraintsCMS.hpp" +#include "gc/g1/jvmFlagConstraintsG1.hpp" +#include "gc/parallel/jvmFlagConstraintsParallel.hpp" #endif #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -57,17 +57,17 @@ // the flag has been set by the user and so should be checked. // As ParallelGCThreads differs among GC modes, we need constraint function. -Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; #if INCLUDE_ALL_GCS status = ParallelGCThreadsConstraintFuncParallel(value, verbose); - if (status != Flag::SUCCESS) { + if (status != JVMFlag::SUCCESS) { return status; } status = ParallelGCThreadsConstraintFuncCMS(value, verbose); - if (status != Flag::SUCCESS) { + if (status != JVMFlag::SUCCESS) { return status; } #endif @@ -77,7 +77,7 @@ Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { // As ConcGCThreads should be smaller than ParallelGCThreads, // we need constraint function. -Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { +JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { #if INCLUDE_ALL_GCS // CMS and G1 GCs use ConcGCThreads. if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) { @@ -85,53 +85,53 @@ Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { "ConcGCThreads (" UINT32_FORMAT ") must be " "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n", value, ParallelGCThreads); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { +static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n", name, value, PLAB::min_size()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif // INCLUDE_ALL_GCS - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { +JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", name, value, PLAB::max_size()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif // INCLUDE_ALL_GCS - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - Flag::Error status = MinPLABSizeBounds(name, value, verbose); +static JVMFlag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { + JVMFlag::Error status = MinPLABSizeBounds(name, value, verbose); - if (status == Flag::SUCCESS) { + if (status == JVMFlag::SUCCESS) { return MaxPLABSizeBounds(name, value, verbose); } return status; } -Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); } -Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { @@ -143,98 +143,98 @@ Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { return status; } -Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { CommandLineError::print(verbose, "MinHeapFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n", value, MaxHeapFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinHeapFreeRatio) { CommandLineError::print(verbose, "MaxHeapFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n", value, MinHeapFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { +static JVMFlag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) { CommandLineError::print(verbose, "Desired lifetime of SoftReferences cannot be expressed correctly. " "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " "(" INTX_FORMAT ") is too large\n", maxHeap, softRef); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { +JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); } -Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { if (value > MarkStackSizeMax) { CommandLineError::print(verbose, "MarkStackSize (" SIZE_FORMAT ") must be " "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n", value, MarkStackSizeMax); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { CommandLineError::print(verbose, "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n", value, MaxMetaspaceFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinMetaspaceFreeRatio) { CommandLineError::print(verbose, "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n", value, MinMetaspaceFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif @@ -247,59 +247,59 @@ Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { "AlwaysTenure=%s\n", NeverTenure ? "true" : "false", AlwaysTenure ? "true" : "false"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { size_t aligned_max = align_down(max_uintx/2, Metaspace::reserve_alignment_words()); if (value > aligned_max) { CommandLineError::print(verbose, "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", value, aligned_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } // To avoid an overflow by 'align_up(value, alignment)'. -static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { +static JVMFlag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1)); if (value > aligned_max) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", name, value, aligned_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { +static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { size_t heap_alignment; #if INCLUDE_ALL_GCS @@ -315,20 +315,20 @@ static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool return MaxSizeForAlignment(name, value, heap_alignment, verbose); } -Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); } -Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { - Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); +JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); - if (status == Flag::SUCCESS) { + if (status == JVMFlag::SUCCESS) { status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); } return status; } -Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) { @@ -336,43 +336,43 @@ Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. " "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n", value, MaxHeapSize, max_uintx); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose); } -Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = NewSizeConstraintFuncG1(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = NewSizeConstraintFuncG1(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { // At least, alignment reserve area is needed. if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { CommandLineError::print(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { CommandLineError::print(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::max_size() * HeapWordSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { // Skip for default value of zero which means set ergonomically. if (FLAG_IS_CMDLINE(TLABSize)) { if (value < MinTLABSize) { @@ -380,22 +380,22 @@ Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { "TLABSize (" SIZE_FORMAT ") must be " "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n", value, MinTLABSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { CommandLineError::print(verbose, "TLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } // We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(), // so AfterMemoryInit type is enough to check. -Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { if (UseTLAB) { size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit(); @@ -405,13 +405,13 @@ Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { "TLABWasteIncrement (" UINTX_FORMAT ") must be " "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n", value, (max_uintx - refill_waste_limit)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { if (FLAG_IS_CMDLINE(SurvivorRatio) && (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) { CommandLineError::print(verbose, @@ -419,52 +419,52 @@ Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", value, (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment())); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value > MaxMetaspaceSize) { CommandLineError::print(verbose, "MetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n", value, MaxMetaspaceSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value < MetaspaceSize) { CommandLineError::print(verbose, "MaxMetaspaceSize (" SIZE_FORMAT ") must be " "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n", value, MaxMetaspaceSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { +JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (value != 0) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value < ObjectAlignmentInBytes) { CommandLineError::print(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", value, ObjectAlignmentInBytes); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp new file mode 100644 index 00000000000..b03409c44a3 --- /dev/null +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP +#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc/cms/jvmFlagConstraintsCMS.hpp" +#include "gc/g1/jvmFlagConstraintsG1.hpp" +#include "gc/parallel/jvmFlagConstraintsParallel.hpp" +#endif + +/* + * Here we have GC arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); +JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); +JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); +JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); +JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); +JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); +JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose); +JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); + +// Internal +JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); + +#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 2bc78f5322f..905bab617ca 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -37,6 +37,7 @@ #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/jvmciCodeInstaller.hpp" #include "jvmci/jvmciRuntime.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" @@ -125,7 +126,7 @@ C2V_VMENTRY(jobject, getFlagValue, (JNIEnv *, jobject c2vm, jobject name_handle) } ResourceMark rm; const char* cstring = java_lang_String::as_utf8_string(name()); - Flag* flag = Flag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); + JVMFlag* flag = JVMFlag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); if (flag == NULL) { return c2vm; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 5318b618110..6d9e1d0c4ea 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -29,6 +29,7 @@ #include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/vmStructs_jvmci.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/resourceHash.hpp" @@ -378,9 +379,9 @@ jobjectArray readConfiguration0(JNIEnv *env, TRAPS) { #define COUNT_FLAG(ignore) +1 #ifdef ASSERT #define CHECK_FLAG(type, name) { \ - Flag* flag = Flag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \ + JVMFlag* flag = JVMFlag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \ assert(flag != NULL, "No such flag named " #name); \ - assert(flag->is_##type(), "Flag " #name " is not of type " #type); \ + assert(flag->is_##type(), "JVMFlag " #name " is not of type " #type); \ } #else #define CHECK_FLAG(type, name) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 605e203b0fe..95d0abfb762 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -35,6 +35,7 @@ #include "oops/oop.hpp" #include "oops/oopHandle.hpp" #include "oops/objArrayKlass.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/thread.hpp" @@ -146,16 +147,16 @@ nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ \ - nonstatic_field(ExceptionTableElement, start_pc, u2) \ - nonstatic_field(ExceptionTableElement, end_pc, u2) \ - nonstatic_field(ExceptionTableElement, handler_pc, u2) \ - nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ + nonstatic_field(ExceptionTableElement, start_pc, u2) \ + nonstatic_field(ExceptionTableElement, end_pc, u2) \ + nonstatic_field(ExceptionTableElement, handler_pc, u2) \ + nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ \ - nonstatic_field(Flag, _type, const char*) \ - nonstatic_field(Flag, _name, const char*) \ - unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) \ - nonstatic_field(Flag, _flags, Flag::Flags) \ - static_field(Flag, flags, Flag*) \ + nonstatic_field(JVMFlag, _type, const char*) \ + nonstatic_field(JVMFlag, _name, const char*) \ + unchecked_nonstatic_field(JVMFlag, _addr, sizeof(void*)) \ + nonstatic_field(JVMFlag, _flags, JVMFlag::Flags) \ + static_field(JVMFlag, flags, JVMFlag*) \ \ nonstatic_field(InstanceKlass, _fields, Array*) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ @@ -345,8 +346,8 @@ declare_toplevel_type(BasicLock) \ declare_toplevel_type(CompilerToVM) \ declare_toplevel_type(ExceptionTableElement) \ - declare_toplevel_type(Flag) \ - declare_toplevel_type(Flag*) \ + declare_toplevel_type(JVMFlag) \ + declare_toplevel_type(JVMFlag*) \ declare_toplevel_type(InvocationCounter) \ declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(LocalVariableTableElement) \ diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 66da16fabe5..a35b1b6a4fd 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -63,7 +63,8 @@ #include "prims/resolvedMethodTable.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/flags/flagSetting.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" @@ -701,7 +702,7 @@ jint universe_init() { AOTLoader::universe_init(); // Checks 'AfterMemoryInit' constraints. - if (!CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterMemoryInit)) { + if (!JVMFlagConstraintList::check_constraints(JVMFlagConstraint::AfterMemoryInit)) { return JNI_EINVAL; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index 40d31912de6..a6bcef24b85 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -38,6 +38,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/copy.hpp" diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index 79753638f77..093c344cce0 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -101,6 +101,7 @@ # include "gc/shared/genCollectedHeap.hpp" # include "gc/shared/generation.hpp" # include "gc/shared/generationCounters.hpp" +# include "gc/shared/jvmFlagConstraintsGC.hpp" # include "gc/shared/modRefBarrierSet.hpp" # include "gc/shared/referencePolicy.hpp" # include "gc/shared/referenceProcessor.hpp" @@ -163,6 +164,13 @@ # include "runtime/extendedPC.hpp" # include "runtime/fieldDescriptor.hpp" # include "runtime/fieldType.hpp" +# include "runtime/flags/flagSetting.hpp" +# include "runtime/flags/jvmFlag.hpp" +# include "runtime/flags/jvmFlagConstraintList.hpp" +# include "runtime/flags/jvmFlagConstraintsCompiler.hpp" +# include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +# include "runtime/flags/jvmFlagRangeList.hpp" +# include "runtime/flags/jvmFlagWriteableList.hpp" # include "runtime/frame.hpp" # include "runtime/frame.inline.hpp" # include "runtime/globals.hpp" @@ -292,6 +300,7 @@ # include "gc/cms/concurrentMarkSweepGeneration.hpp" # include "gc/cms/freeChunk.hpp" # include "gc/cms/gSpaceCounters.hpp" +# include "gc/cms/jvmFlagConstraintsCMS.hpp" # include "gc/cms/parOopClosures.hpp" # include "gc/cms/promotionInfo.hpp" # include "gc/cms/yieldingWorkgroup.hpp" @@ -299,10 +308,12 @@ # include "gc/g1/g1BlockOffsetTable.hpp" # include "gc/g1/g1OopClosures.hpp" # include "gc/g1/g1_globals.hpp" +# include "gc/g1/jvmFlagConstraintsG1.hpp" # include "gc/g1/ptrQueue.hpp" # include "gc/g1/satbMarkQueue.hpp" # include "gc/parallel/gcAdaptivePolicyCounters.hpp" # include "gc/parallel/immutableSpace.hpp" +# include "gc/parallel/jvmFlagConstraintsParallel.hpp" # include "gc/parallel/mutableSpace.hpp" # include "gc/parallel/objectStartArray.hpp" # include "gc/parallel/parMarkBitMap.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 44913f41868..3646046a00b 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -53,6 +53,7 @@ #include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -971,29 +972,29 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) WB_END template -static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAt)(const char*, T*, bool, bool)) { +static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, JVMFlag::Error (*TAt)(const char*, T*, bool, bool)) { if (name == NULL) { return false; } ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); - Flag::Error result = (*TAt)(flag_name, value, true, true); + JVMFlag::Error result = (*TAt)(flag_name, value, true, true); env->ReleaseStringUTFChars(name, flag_name); - return (result == Flag::SUCCESS); + return (result == JVMFlag::SUCCESS); } template -static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAtPut)(const char*, T*, Flag::Flags)) { +static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, JVMFlag::Error (*TAtPut)(const char*, T*, JVMFlag::Flags)) { if (name == NULL) { return false; } ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); - Flag::Error result = (*TAtPut)(flag_name, value, Flag::INTERNAL); + JVMFlag::Error result = (*TAtPut)(flag_name, value, JVMFlag::INTERNAL); env->ReleaseStringUTFChars(name, flag_name); - return (result == Flag::SUCCESS); + return (result == JVMFlag::SUCCESS); } template @@ -1026,28 +1027,28 @@ static jobject doubleBox(JavaThread* thread, JNIEnv* env, jdouble value) { return box(thread, env, vmSymbols::java_lang_Double(), vmSymbols::Double_valueOf_signature(), value); } -static Flag* getVMFlag(JavaThread* thread, JNIEnv* env, jstring name) { +static JVMFlag* getVMFlag(JavaThread* thread, JNIEnv* env, jstring name) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, NULL); - Flag* result = Flag::find_flag(flag_name, strlen(flag_name), true, true); + JVMFlag* result = JVMFlag::find_flag(flag_name, strlen(flag_name), true, true); env->ReleaseStringUTFChars(name, flag_name); return result; } WB_ENTRY(jboolean, WB_IsConstantVMFlag(JNIEnv* env, jobject o, jstring name)) - Flag* flag = getVMFlag(thread, env, name); + JVMFlag* flag = getVMFlag(thread, env, name); return (flag != NULL) && flag->is_constant_in_binary(); WB_END WB_ENTRY(jboolean, WB_IsLockedVMFlag(JNIEnv* env, jobject o, jstring name)) - Flag* flag = getVMFlag(thread, env, name); + JVMFlag* flag = getVMFlag(thread, env, name); return (flag != NULL) && !(flag->is_unlocked() || flag->is_unlocker()); WB_END WB_ENTRY(jobject, WB_GetBooleanVMFlag(JNIEnv* env, jobject o, jstring name)) bool result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::boolAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::boolAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return booleanBox(thread, env, result); } @@ -1056,7 +1057,7 @@ WB_END WB_ENTRY(jobject, WB_GetIntVMFlag(JNIEnv* env, jobject o, jstring name)) int result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::intAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::intAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1065,7 +1066,7 @@ WB_END WB_ENTRY(jobject, WB_GetUintVMFlag(JNIEnv* env, jobject o, jstring name)) uint result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uintAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::uintAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1074,7 +1075,7 @@ WB_END WB_ENTRY(jobject, WB_GetIntxVMFlag(JNIEnv* env, jobject o, jstring name)) intx result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::intxAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::intxAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1083,7 +1084,7 @@ WB_END WB_ENTRY(jobject, WB_GetUintxVMFlag(JNIEnv* env, jobject o, jstring name)) uintx result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uintxAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::uintxAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1092,7 +1093,7 @@ WB_END WB_ENTRY(jobject, WB_GetUint64VMFlag(JNIEnv* env, jobject o, jstring name)) uint64_t result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::uint64_tAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1101,7 +1102,7 @@ WB_END WB_ENTRY(jobject, WB_GetSizeTVMFlag(JNIEnv* env, jobject o, jstring name)) uintx result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::size_tAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1110,7 +1111,7 @@ WB_END WB_ENTRY(jobject, WB_GetDoubleVMFlag(JNIEnv* env, jobject o, jstring name)) double result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::doubleAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return doubleBox(thread, env, result); } @@ -1119,7 +1120,7 @@ WB_END WB_ENTRY(jstring, WB_GetStringVMFlag(JNIEnv* env, jobject o, jstring name)) ccstr ccstrResult; - if (GetVMFlag (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAt)) { + if (GetVMFlag (thread, env, name, &ccstrResult, &JVMFlag::ccstrAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI jstring result = env->NewStringUTF(ccstrResult); CHECK_JNI_EXCEPTION_(env, NULL); @@ -1130,42 +1131,42 @@ WB_END WB_ENTRY(void, WB_SetBooleanVMFlag(JNIEnv* env, jobject o, jstring name, jboolean value)) bool result = value == JNI_TRUE ? true : false; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::boolAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::boolAtPut); WB_END WB_ENTRY(void, WB_SetIntVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) int result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::intAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::intAtPut); WB_END WB_ENTRY(void, WB_SetUintVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uint result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::uintAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::uintAtPut); WB_END WB_ENTRY(void, WB_SetIntxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) intx result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::intxAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::intxAtPut); WB_END WB_ENTRY(void, WB_SetUintxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uintx result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::uintxAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::uintxAtPut); WB_END WB_ENTRY(void, WB_SetUint64VMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uint64_t result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::uint64_tAtPut); WB_END WB_ENTRY(void, WB_SetSizeTVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) size_t result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::size_tAtPut); WB_END WB_ENTRY(void, WB_SetDoubleVMFlag(JNIEnv* env, jobject o, jstring name, jdouble value)) double result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::doubleAtPut); WB_END WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring value)) @@ -1182,7 +1183,7 @@ WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring bool needFree; { ThreadInVMfromNative ttvfn(thread); // back to VM - needFree = SetVMFlag (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAtPut); + needFree = SetVMFlag (thread, env, name, &ccstrResult, &JVMFlag::ccstrAtPut); } if (value != NULL) { env->ReleaseStringUTFChars(value, ccstrValue); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 874c86a018d..1e49fe1d35d 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -42,10 +42,10 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/arguments_ext.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "runtime/os.inline.hpp" @@ -739,7 +739,7 @@ static bool verify_special_jvm_flags() { // if flag has become obsolete it should not have a "globals" flag defined anymore. if (!version_less_than(JDK_Version::current(), flag.obsolete_in)) { - if (Flag::find_flag(flag.name) != NULL) { + if (JVMFlag::find_flag(flag.name) != NULL) { // Temporarily disable the warning: 8196739 // warning("Global variable for obsolete special flag entry \"%s\" should be removed", flag.name); } @@ -749,7 +749,7 @@ static bool verify_special_jvm_flags() { if (!flag.expired_in.is_undefined()) { // if flag has become expired it should not have a "globals" flag defined anymore. if (!version_less_than(JDK_Version::current(), flag.expired_in)) { - if (Flag::find_flag(flag.name) != NULL) { + if (JVMFlag::find_flag(flag.name) != NULL) { // Temporarily disable the warning: 8196739 // warning("Global variable for expired flag entry \"%s\" should be removed", flag.name); } @@ -833,15 +833,15 @@ void Arguments::describe_range_error(ArgsRange errcode) { } } -static bool set_bool_flag(const char* name, bool value, Flag::Flags origin) { - if (CommandLineFlags::boolAtPut(name, &value, origin) == Flag::SUCCESS) { +static bool set_bool_flag(const char* name, bool value, JVMFlag::Flags origin) { + if (JVMFlag::boolAtPut(name, &value, origin) == JVMFlag::SUCCESS) { return true; } else { return false; } } -static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origin) { +static bool set_fp_numeric_flag(const char* name, char* value, JVMFlag::Flags origin) { char* end; errno = 0; double v = strtod(value, &end); @@ -849,18 +849,18 @@ static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origi return false; } - if (CommandLineFlags::doubleAtPut(name, &v, origin) == Flag::SUCCESS) { + if (JVMFlag::doubleAtPut(name, &v, origin) == JVMFlag::SUCCESS) { return true; } return false; } -static bool set_numeric_flag(const char* name, char* value, Flag::Flags origin) { +static bool set_numeric_flag(const char* name, char* value, JVMFlag::Flags origin) { julong v; int int_v; intx intx_v; bool is_neg = false; - Flag* result = Flag::find_flag(name, strlen(name)); + JVMFlag* result = JVMFlag::find_flag(name, strlen(name)); if (result == NULL) { return false; @@ -882,43 +882,43 @@ static bool set_numeric_flag(const char* name, char* value, Flag::Flags origin) if (is_neg) { int_v = -int_v; } - return CommandLineFlags::intAtPut(result, &int_v, origin) == Flag::SUCCESS; + return JVMFlag::intAtPut(result, &int_v, origin) == JVMFlag::SUCCESS; } else if (result->is_uint()) { uint uint_v = (uint) v; - return CommandLineFlags::uintAtPut(result, &uint_v, origin) == Flag::SUCCESS; + return JVMFlag::uintAtPut(result, &uint_v, origin) == JVMFlag::SUCCESS; } else if (result->is_intx()) { intx_v = (intx) v; if (is_neg) { intx_v = -intx_v; } - return CommandLineFlags::intxAtPut(result, &intx_v, origin) == Flag::SUCCESS; + return JVMFlag::intxAtPut(result, &intx_v, origin) == JVMFlag::SUCCESS; } else if (result->is_uintx()) { uintx uintx_v = (uintx) v; - return CommandLineFlags::uintxAtPut(result, &uintx_v, origin) == Flag::SUCCESS; + return JVMFlag::uintxAtPut(result, &uintx_v, origin) == JVMFlag::SUCCESS; } else if (result->is_uint64_t()) { uint64_t uint64_t_v = (uint64_t) v; - return CommandLineFlags::uint64_tAtPut(result, &uint64_t_v, origin) == Flag::SUCCESS; + return JVMFlag::uint64_tAtPut(result, &uint64_t_v, origin) == JVMFlag::SUCCESS; } else if (result->is_size_t()) { size_t size_t_v = (size_t) v; - return CommandLineFlags::size_tAtPut(result, &size_t_v, origin) == Flag::SUCCESS; + return JVMFlag::size_tAtPut(result, &size_t_v, origin) == JVMFlag::SUCCESS; } else if (result->is_double()) { double double_v = (double) v; - return CommandLineFlags::doubleAtPut(result, &double_v, origin) == Flag::SUCCESS; + return JVMFlag::doubleAtPut(result, &double_v, origin) == JVMFlag::SUCCESS; } else { return false; } } -static bool set_string_flag(const char* name, const char* value, Flag::Flags origin) { - if (CommandLineFlags::ccstrAtPut(name, &value, origin) != Flag::SUCCESS) return false; - // Contract: CommandLineFlags always returns a pointer that needs freeing. +static bool set_string_flag(const char* name, const char* value, JVMFlag::Flags origin) { + if (JVMFlag::ccstrAtPut(name, &value, origin) != JVMFlag::SUCCESS) return false; + // Contract: JVMFlag always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); return true; } -static bool append_to_string_flag(const char* name, const char* new_value, Flag::Flags origin) { +static bool append_to_string_flag(const char* name, const char* new_value, JVMFlag::Flags origin) { const char* old_value = ""; - if (CommandLineFlags::ccstrAt(name, &old_value) != Flag::SUCCESS) return false; + if (JVMFlag::ccstrAt(name, &old_value) != JVMFlag::SUCCESS) return false; size_t old_len = old_value != NULL ? strlen(old_value) : 0; size_t new_len = strlen(new_value); const char* value; @@ -935,11 +935,11 @@ static bool append_to_string_flag(const char* name, const char* new_value, Flag: value = buf; free_this_too = buf; } - (void) CommandLineFlags::ccstrAtPut(name, &value, origin); - // CommandLineFlags always returns a pointer that needs freeing. + (void) JVMFlag::ccstrAtPut(name, &value, origin); + // JVMFlag always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); if (free_this_too != NULL) { - // CommandLineFlags made its own copy, so I must delete my own temp. buffer. + // JVMFlag made its own copy, so I must delete my own temp. buffer. FREE_C_HEAP_ARRAY(char, free_this_too); } return true; @@ -1010,7 +1010,7 @@ AliasedLoggingFlag Arguments::catch_logging_aliases(const char* name, bool on){ return a; } -bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { +bool Arguments::parse_argument(const char* arg, JVMFlag::Flags origin) { // range of acceptable characters spelled out for portability reasons #define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]" @@ -1048,7 +1048,7 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { char punct; if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "%c", name, &punct) == 2 && punct == '=') { const char* value = strchr(arg, '=') + 1; - Flag* flag; + JVMFlag* flag; // this scanf pattern matches both strings (handled here) and numbers (handled later)) AliasedLoggingFlag alf = catch_logging_aliases(name, true); @@ -1060,7 +1060,7 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { if (real_name == NULL) { return false; } - flag = Flag::find_flag(real_name); + flag = JVMFlag::find_flag(real_name); if (flag != NULL && flag->is_ccstr()) { if (flag->ccstr_accumulates()) { return append_to_string_flag(real_name, value, origin); @@ -1221,7 +1221,7 @@ void Arguments::print_jvm_args_on(outputStream* st) { bool Arguments::process_argument(const char* arg, jboolean ignore_unrecognized, - Flag::Flags origin) { + JVMFlag::Flags origin) { JDK_Version since = JDK_Version(); if (parse_argument(arg, origin)) { @@ -1266,10 +1266,10 @@ bool Arguments::process_argument(const char* arg, // For locked flags, report a custom error message if available. // Otherwise, report the standard unrecognized VM option. - Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true, true); + JVMFlag* found_flag = JVMFlag::find_flag((const char*)argname, arg_len, true, true); if (found_flag != NULL) { char locked_message_buf[BUFLEN]; - Flag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN); + JVMFlag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN); if (strlen(locked_message_buf) == 0) { if (found_flag->is_bool() && !has_plus_minus) { jio_fprintf(defaultStream::error_stream(), @@ -1283,8 +1283,8 @@ bool Arguments::process_argument(const char* arg, } } else { #ifdef PRODUCT - bool mismatched = ((msg_type == Flag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) || - (msg_type == Flag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD)); + bool mismatched = ((msg_type == JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) || + (msg_type == JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD)); if (ignore_unrecognized && mismatched) { return true; } @@ -1297,7 +1297,7 @@ bool Arguments::process_argument(const char* arg, } jio_fprintf(defaultStream::error_stream(), "Unrecognized VM option '%s'\n", argname); - Flag* fuzzy_matched = Flag::fuzzy_match((const char*)argname, arg_len, true); + JVMFlag* fuzzy_matched = JVMFlag::fuzzy_match((const char*)argname, arg_len, true); if (fuzzy_matched != NULL) { jio_fprintf(defaultStream::error_stream(), "Did you mean '%s%s%s'? ", @@ -1350,7 +1350,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, // this allows a way to include spaces in string-valued options token[pos] = '\0'; logOption(token); - result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); build_jvm_flags(token); pos = 0; in_white_space = true; @@ -1368,7 +1368,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } if (pos > 0) { token[pos] = '\0'; - result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); build_jvm_flags(token); } fclose(stream); @@ -1991,10 +1991,10 @@ jint Arguments::set_aggressive_heap_flags() { initHeapSize = limit_by_allocatable_memory(initHeapSize); if (FLAG_IS_DEFAULT(MaxHeapSize)) { - if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Currently the minimum size and the initial heap sizes are the same. @@ -2003,10 +2003,10 @@ jint Arguments::set_aggressive_heap_flags() { if (FLAG_IS_DEFAULT(NewSize)) { // Make the young generation 3/8ths of the total heap. if (FLAG_SET_CMDLINE(size_t, NewSize, - ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != Flag::SUCCESS) { + ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2016,20 +2016,20 @@ jint Arguments::set_aggressive_heap_flags() { #endif // Increase some data structure sizes for efficiency - if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // See the OldPLABSize comment below, but replace 'after promotion' // with 'after copying'. YoungPLABSize is the size of the survivor // space per-gc-thread buffers. The default is 4kw. - if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != Flag::SUCCESS) { // Note: this is in words + if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != JVMFlag::SUCCESS) { // Note: this is in words return JNI_EINVAL; } @@ -2046,29 +2046,29 @@ jint Arguments::set_aggressive_heap_flags() { // locality. A minor effect may be that larger PLABs reduce the // number of PLAB allocation events during gc. The value of 8kw // was arrived at by experimenting with specjbb. - if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != Flag::SUCCESS) { // Note: this is in words + if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != JVMFlag::SUCCESS) { // Note: this is in words return JNI_EINVAL; } // Enable parallel GC and adaptive generation sizing - if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Encourage steady state memory management - if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // This appears to improve mutator locality - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Get around early Solaris scheduling bug // (affinity vs other jobs on system) // but disallow DR and offlining (5008695). - if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } @@ -2409,20 +2409,20 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, // Parse args structure generated from JAVA_TOOL_OPTIONS environment // variable (if present). - jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); + jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Parse args structure generated from the command line flags. - result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, Flag::COMMAND_LINE); + result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, JVMFlag::COMMAND_LINE); if (result != JNI_OK) { return result; } // Parse args structure generated from the _JAVA_OPTIONS environment // variable (if present) (mimics classic VM) - result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); + result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); if (result != JNI_OK) { return result; } @@ -2566,7 +2566,7 @@ jint Arguments::parse_xss(const JavaVMOption* option, const char* tail, intx* ou return JNI_OK; } -jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin) { +jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin) { // For match_option to return remaining or value part of option string const char* tail; @@ -2599,7 +2599,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m } else if (!strcmp(tail, ":gc")) { LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc)); } else if (!strcmp(tail, ":jni")) { - if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2736,24 +2736,24 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_enable_preview(); // -Xnoclassgc } else if (match_option(option, "-Xnoclassgc")) { - if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xconcgc } else if (match_option(option, "-Xconcgc")) { - if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } handle_extra_cms_flags("-Xconcgc uses UseConcMarkSweepGC"); // -Xnoconcgc } else if (match_option(option, "-Xnoconcgc")) { - if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } handle_extra_cms_flags("-Xnoconcgc uses UseConcMarkSweepGC"); // -Xbatch } else if (match_option(option, "-Xbatch")) { - if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xmn for compatibility with other JVM vendors @@ -2766,10 +2766,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m describe_range_error(errcode); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xms @@ -2786,7 +2786,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_min_heap_size((size_t)long_initial_heap_size); // Currently the minimum size and the initial heap sizes are the same. // Can be overridden with -XX:InitialHeapSize. - if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xmx @@ -2799,7 +2799,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m describe_range_error(errcode); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Xmaxf @@ -2812,7 +2812,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m option->optionString); return JNI_EINVAL; } else { - if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2826,7 +2826,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m option->optionString); return JNI_EINVAL; } else { - if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2837,7 +2837,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m if (err != JNI_OK) { return err; } - if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-Xmaxjitcodesize", &tail) || @@ -2850,7 +2850,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m "Invalid maximum code cache size: %s.\n", option->optionString); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -green @@ -2864,7 +2864,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xrs } else if (match_option(option, "-Xrs")) { // Classic/EVM option, new functionality - if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xprof @@ -2875,17 +2875,17 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m warning("Ignoring option %s; support was removed in %s", option->optionString, version); // -Xconcurrentio } else if (match_option(option, "-Xconcurrentio")) { - if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } SafepointSynchronize::set_defer_thr_suspend_loop_count(); - if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != Flag::SUCCESS) { // 20Kb per thread added to new generation + if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != JVMFlag::SUCCESS) { // 20Kb per thread added to new generation return JNI_EINVAL; } @@ -2897,7 +2897,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m #ifndef PRODUCT // -Xprintflags } else if (match_option(option, "-Xprintflags")) { - CommandLineFlags::printFlags(tty, false); + JVMFlag::printFlags(tty, false); vm_exit(0); #endif // -D @@ -2932,7 +2932,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // Out of the box management support if (match_option(option, "-Dcom.sun.management", &tail)) { #if INCLUDE_MANAGEMENT - if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // management agent in module jdk.management.agent @@ -2957,55 +2957,55 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_mode_flags(_comp); // -Xshare:dump } else if (match_option(option, "-Xshare:dump")) { - if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } set_mode_flags(_int); // Prevent compilation, which creates objects // -Xshare:on } else if (match_option(option, "-Xshare:on")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xshare:auto } else if (match_option(option, "-Xshare:auto")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xshare:off } else if (match_option(option, "-Xshare:off")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xverify } else if (match_option(option, "-Xverify", &tail)) { if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (strcmp(tail, ":remote") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (strcmp(tail, ":none") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (is_bad_option(option, args->ignoreUnrecognized, "verification")) { @@ -3064,23 +3064,23 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure; // and the last option wins. } else if (match_option(option, "-XX:+NeverTenure")) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+AlwaysTenure")) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) { @@ -3091,51 +3091,51 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != JVMFlag::SUCCESS) { return JNI_EINVAL; } if (MaxTenuringThreshold == 0) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } } else if (match_option(option, "-XX:+DisplayVMOutputToStderr")) { - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+DisplayVMOutputToStdout")) { - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+ExtendedDTraceProbes")) { #if defined(DTRACE_ENABLED) - if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } #else // defined(DTRACE_ENABLED) @@ -3145,11 +3145,11 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m #endif // defined(DTRACE_ENABLED) #ifdef ASSERT } else if (match_option(option, "-XX:+FullGCALot")) { - if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // disable scavenge before parallel mark-compact - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } #endif @@ -3178,10 +3178,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xshare:on // -Xlog:class+path=info if (PrintSharedArchiveAndExit) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(class, path)); @@ -3856,7 +3856,7 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, continue; } if (match_option(option, "-XX:+PrintFlagsInitial")) { - CommandLineFlags::printFlags(tty, false); + JVMFlag::printFlags(tty, false); vm_exit(0); } if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { @@ -3885,13 +3885,13 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, #ifndef PRODUCT if (match_option(option, "-XX:+PrintFlagsWithComments")) { - CommandLineFlags::printFlags(tty, true); + JVMFlag::printFlags(tty, true); vm_exit(0); } #endif if (match_option(option, "-XX:+UseAppCDS")) { - Flag* flag = Flag::find_flag("SharedArchiveFile", 17, true, true); + JVMFlag* flag = JVMFlag::find_flag("SharedArchiveFile", 17, true, true); if (flag->is_diagnostic()) { flag->clear_diagnostic(); } @@ -3947,9 +3947,9 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { assert(verify_special_jvm_flags(), "deprecated and obsolete flag table inconsistent"); // Initialize ranges, constraints and writeables - CommandLineFlagRangeList::init(); - CommandLineFlagConstraintList::init(); - CommandLineFlagWriteableList::init(); + JVMFlagRangeList::init(); + JVMFlagConstraintList::init(); + JVMFlagWriteableList::init(); // If flag "-XX:Flags=flags-file" is used it will be the first option to be processed. const char* hotspotrc = ".hotspotrc"; @@ -4250,7 +4250,7 @@ jint Arguments::apply_ergo() { #endif // PRODUCT if (PrintCommandLineFlags) { - CommandLineFlags::printSetFlags(tty); + JVMFlag::printSetFlags(tty); } // Apply CPU specific policy for the BiasedLocking diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 83dd78fff81..edf88193673 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -28,6 +28,7 @@ #include "logging/logLevel.hpp" #include "logging/logTag.hpp" #include "memory/allocation.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" @@ -413,8 +414,8 @@ class Arguments : AllStatic { // Argument parsing static void do_pd_flag_adjustments(); - static bool parse_argument(const char* arg, Flag::Flags origin); - static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin); + static bool parse_argument(const char* arg, JVMFlag::Flags origin); + static bool process_argument(const char* arg, jboolean ignore_unrecognized, JVMFlag::Flags origin); static void process_java_launcher_argument(const char*, void*); static void process_java_compiler_argument(const char* arg); static jint parse_options_environment_variable(const char* name, ScopedVMInitArgs* vm_args); @@ -442,7 +443,7 @@ class Arguments : AllStatic { static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin); static jint finalize_vm_init_args(bool patch_mod_javabase); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp deleted file mode 100644 index 6700bb1da4d..00000000000 --- a/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP - -#include "runtime/globals.hpp" -#include "utilities/growableArray.hpp" - -/* - * Here we have a mechanism for extracting constraints (as custom functions) for flags, - * which otherwise can not be expressed via simple range check, specified in flag macro tables. - * - * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change. - * - * See runtime "runtime/commandLineFlagConstraintsCompiler.hpp", - * "runtime/commandLineFlagConstraintsGC.hpp" and - * "runtime/commandLineFlagConstraintsRuntime.hpp" for the functions themselves. - */ - -typedef Flag::Error (*CommandLineFlagConstraintFunc_bool)(bool value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_int)(int value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_intx)(intx value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_uint)(uint value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_uintx)(uintx value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(size_t value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(double value, bool verbose); - -class CommandLineFlagConstraint : public CHeapObj { -public: - // During VM initialization, constraint validation will be done order of ConstraintType. - enum ConstraintType { - // Will be validated during argument processing (Arguments::parse_argument). - AtParse = 0, - // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). - AfterErgo = 1, - // Will be validated inside universe_init(), right after Metaspace::global_initialize(). - AfterMemoryInit = 2 - }; - -private: - const char* _name; - ConstraintType _validate_type; - -public: - // the "name" argument must be a string literal - CommandLineFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; - ~CommandLineFlagConstraint() {}; - const char* name() const { return _name; } - ConstraintType type() const { return _validate_type; } - virtual Flag::Error apply(bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; -}; - -class CommandLineFlagConstraintList : public AllStatic { -private: - static GrowableArray* _constraints; - // Latest constraint validation type. - static CommandLineFlagConstraint::ConstraintType _validating_type; -public: - static void init(); - static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } - static CommandLineFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } - static CommandLineFlagConstraint* find(const char* name); - static CommandLineFlagConstraint* find_if_needs_check(const char* name); - static void add(CommandLineFlagConstraint* constraint) { _constraints->append(constraint); } - // True if 'AfterErgo' or later constraint functions are validated. - static bool validated_after_ergo() { return _validating_type >= CommandLineFlagConstraint::AfterErgo; }; - static bool check_constraints(CommandLineFlagConstraint::ConstraintType type); -}; - -#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp deleted file mode 100644 index b0596e93a19..00000000000 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP - -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" - -/* - * Here we have compiler arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -Flag::Error AliasLevelConstraintFunc(intx value, bool verbose); - -Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose); - -Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); - -Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); - -Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); - -Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose); - -Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); - -Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); - -Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); - -Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); - -Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); - -Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); - -Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); - -Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); - -Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose); - -#ifdef COMPILER2 -Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); - -Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); -#endif - -Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose); - -#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/src/hotspot/share/runtime/flags/flagSetting.hpp b/src/hotspot/share/runtime/flags/flagSetting.hpp new file mode 100644 index 00000000000..f2f629b0fb3 --- /dev/null +++ b/src/hotspot/share/runtime/flags/flagSetting.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP +#define SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP + +#include "memory/allocation.hpp" + +// debug flags control various aspects of the VM and are global accessible + +// use FlagSetting to temporarily change some debug flag +// e.g. FlagSetting fs(DebugThisAndThat, true); +// restored to previous value upon leaving scope +class FlagSetting : public StackObj { + bool val; + bool* flag; +public: + FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; } + ~FlagSetting() { *flag = val; } +}; + +class UIntFlagSetting : public StackObj { + uint val; + uint* flag; +public: + UIntFlagSetting(uint& fl, uint newValue) { flag = &fl; val = fl; fl = newValue; } + ~UIntFlagSetting() { *flag = val; } +}; + +class SizeTFlagSetting : public StackObj { + size_t val; + size_t* flag; +public: + SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } + ~SizeTFlagSetting() { *flag = val; } +}; + +// Helper class for temporarily saving the value of a flag during a scope. +template +class FlagGuard { + unsigned char _value[SIZE]; + void* const _addr; +public: + FlagGuard(void* flag_addr) : _addr(flag_addr) { memcpy(_value, _addr, SIZE); } + ~FlagGuard() { memcpy(_addr, _value, SIZE); } +}; + +#define FLAG_GUARD(f) FlagGuard f ## _guard(&f) + +#endif // SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp new file mode 100644 index 00000000000..b6f6b55f2ea --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -0,0 +1,1506 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/globals_extension.hpp" +#include "trace/tracing.hpp" +#include "utilities/defaultStream.hpp" +#include "utilities/stringUtils.hpp" + +#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 +static char* create_range_str(const char *fmt, ...) { + static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; + static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); + + int size_needed = 0; + do { + va_list args; + va_start(args, fmt); + size_needed = jio_vsnprintf(range_string, string_length, fmt, args); + va_end(args); + + if (size_needed < 0) { + string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; + range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); + guarantee(range_string != NULL, "create_range_str string should not be NULL"); + } + } while (size_needed < 0); + + return range_string; +} + +const char* JVMFlag::get_int_default_range_str() { + return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); +} + +const char* JVMFlag::get_uint_default_range_str() { + return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); +} + +const char* JVMFlag::get_intx_default_range_str() { + return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); +} + +const char* JVMFlag::get_uintx_default_range_str() { + return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); +} + +const char* JVMFlag::get_uint64_t_default_range_str() { + return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); +} + +const char* JVMFlag::get_size_t_default_range_str() { + return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); +} + +const char* JVMFlag::get_double_default_range_str() { + return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); +} + +static bool is_product_build() { +#ifdef PRODUCT + return true; +#else + return false; +#endif +} + +JVMFlag::Error JVMFlag::check_writable(bool changed) { + if (is_constant_in_binary()) { + fatal("flag is constant: %s", _name); + } + + JVMFlag::Error error = JVMFlag::SUCCESS; + if (changed) { + JVMFlagWriteable* writeable = JVMFlagWriteableList::find(_name); + if (writeable) { + if (writeable->is_writeable() == false) { + switch (writeable->type()) + { + case JVMFlagWriteable::Once: + error = JVMFlag::SET_ONLY_ONCE; + jio_fprintf(defaultStream::error_stream(), "Error: %s may not be set more than once\n", _name); + break; + case JVMFlagWriteable::CommandLineOnly: + error = JVMFlag::COMMAND_LINE_ONLY; + jio_fprintf(defaultStream::error_stream(), "Error: %s may be modified only from commad line\n", _name); + break; + default: + ShouldNotReachHere(); + break; + } + } + writeable->mark_once(); + } + } + return error; +} + +bool JVMFlag::is_bool() const { + return strcmp(_type, "bool") == 0; +} + +bool JVMFlag::get_bool() const { + return *((bool*) _addr); +} + +JVMFlag::Error JVMFlag::set_bool(bool value) { + JVMFlag::Error error = check_writable(value!=get_bool()); + if (error == JVMFlag::SUCCESS) { + *((bool*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_int() const { + return strcmp(_type, "int") == 0; +} + +int JVMFlag::get_int() const { + return *((int*) _addr); +} + +JVMFlag::Error JVMFlag::set_int(int value) { + JVMFlag::Error error = check_writable(value!=get_int()); + if (error == JVMFlag::SUCCESS) { + *((int*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_uint() const { + return strcmp(_type, "uint") == 0; +} + +uint JVMFlag::get_uint() const { + return *((uint*) _addr); +} + +JVMFlag::Error JVMFlag::set_uint(uint value) { + JVMFlag::Error error = check_writable(value!=get_uint()); + if (error == JVMFlag::SUCCESS) { + *((uint*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_intx() const { + return strcmp(_type, "intx") == 0; +} + +intx JVMFlag::get_intx() const { + return *((intx*) _addr); +} + +JVMFlag::Error JVMFlag::set_intx(intx value) { + JVMFlag::Error error = check_writable(value!=get_intx()); + if (error == JVMFlag::SUCCESS) { + *((intx*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_uintx() const { + return strcmp(_type, "uintx") == 0; +} + +uintx JVMFlag::get_uintx() const { + return *((uintx*) _addr); +} + +JVMFlag::Error JVMFlag::set_uintx(uintx value) { + JVMFlag::Error error = check_writable(value!=get_uintx()); + if (error == JVMFlag::SUCCESS) { + *((uintx*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_uint64_t() const { + return strcmp(_type, "uint64_t") == 0; +} + +uint64_t JVMFlag::get_uint64_t() const { + return *((uint64_t*) _addr); +} + +JVMFlag::Error JVMFlag::set_uint64_t(uint64_t value) { + JVMFlag::Error error = check_writable(value!=get_uint64_t()); + if (error == JVMFlag::SUCCESS) { + *((uint64_t*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_size_t() const { + return strcmp(_type, "size_t") == 0; +} + +size_t JVMFlag::get_size_t() const { + return *((size_t*) _addr); +} + +JVMFlag::Error JVMFlag::set_size_t(size_t value) { + JVMFlag::Error error = check_writable(value!=get_size_t()); + if (error == JVMFlag::SUCCESS) { + *((size_t*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_double() const { + return strcmp(_type, "double") == 0; +} + +double JVMFlag::get_double() const { + return *((double*) _addr); +} + +JVMFlag::Error JVMFlag::set_double(double value) { + JVMFlag::Error error = check_writable(value!=get_double()); + if (error == JVMFlag::SUCCESS) { + *((double*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_ccstr() const { + return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; +} + +bool JVMFlag::ccstr_accumulates() const { + return strcmp(_type, "ccstrlist") == 0; +} + +ccstr JVMFlag::get_ccstr() const { + return *((ccstr*) _addr); +} + +JVMFlag::Error JVMFlag::set_ccstr(ccstr value) { + JVMFlag::Error error = check_writable(value!=get_ccstr()); + if (error == JVMFlag::SUCCESS) { + *((ccstr*) _addr) = value; + } + return error; +} + + +JVMFlag::Flags JVMFlag::get_origin() { + return Flags(_flags & VALUE_ORIGIN_MASK); +} + +void JVMFlag::set_origin(Flags origin) { + assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); + Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); + _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); +} + +bool JVMFlag::is_default() { + return (get_origin() == DEFAULT); +} + +bool JVMFlag::is_ergonomic() { + return (get_origin() == ERGONOMIC); +} + +bool JVMFlag::is_command_line() { + return (_flags & ORIG_COMMAND_LINE) != 0; +} + +void JVMFlag::set_command_line() { + _flags = Flags(_flags | ORIG_COMMAND_LINE); +} + +bool JVMFlag::is_product() const { + return (_flags & KIND_PRODUCT) != 0; +} + +bool JVMFlag::is_manageable() const { + return (_flags & KIND_MANAGEABLE) != 0; +} + +bool JVMFlag::is_diagnostic() const { + return (_flags & KIND_DIAGNOSTIC) != 0; +} + +bool JVMFlag::is_experimental() const { + return (_flags & KIND_EXPERIMENTAL) != 0; +} + +bool JVMFlag::is_notproduct() const { + return (_flags & KIND_NOT_PRODUCT) != 0; +} + +bool JVMFlag::is_develop() const { + return (_flags & KIND_DEVELOP) != 0; +} + +bool JVMFlag::is_read_write() const { + return (_flags & KIND_READ_WRITE) != 0; +} + +bool JVMFlag::is_commercial() const { + return (_flags & KIND_COMMERCIAL) != 0; +} + +/** + * Returns if this flag is a constant in the binary. Right now this is + * true for notproduct and develop flags in product builds. + */ +bool JVMFlag::is_constant_in_binary() const { +#ifdef PRODUCT + return is_notproduct() || is_develop(); +#else + return false; +#endif +} + +bool JVMFlag::is_unlocker() const { + return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || + strcmp(_name, "UnlockExperimentalVMOptions") == 0 || + is_unlocker_ext(); +} + +bool JVMFlag::is_unlocked() const { + if (is_diagnostic()) { + return UnlockDiagnosticVMOptions; + } + if (is_experimental()) { + return UnlockExperimentalVMOptions; + } + return is_unlocked_ext(); +} + +void JVMFlag::clear_diagnostic() { + assert(is_diagnostic(), "sanity"); + _flags = Flags(_flags & ~KIND_DIAGNOSTIC); + assert(!is_diagnostic(), "sanity"); +} + +// Get custom message for this locked flag, or NULL if +// none is available. Returns message type produced. +JVMFlag::MsgType JVMFlag::get_locked_message(char* buf, int buflen) const { + buf[0] = '\0'; + if (is_diagnostic() && !is_unlocked()) { + jio_snprintf(buf, buflen, + "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" + "Error: The unlock option must precede '%s'.\n", + _name, _name); + return JVMFlag::DIAGNOSTIC_FLAG_BUT_LOCKED; + } + if (is_experimental() && !is_unlocked()) { + jio_snprintf(buf, buflen, + "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" + "Error: The unlock option must precede '%s'.\n", + _name, _name); + return JVMFlag::EXPERIMENTAL_FLAG_BUT_LOCKED; + } + if (is_develop() && is_product_build()) { + jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", + _name); + return JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; + } + if (is_notproduct() && is_product_build()) { + jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", + _name); + return JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; + } + return get_locked_message_ext(buf, buflen); +} + +bool JVMFlag::is_writeable() const { + return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); +} + +// All flags except "manageable" are assumed to be internal flags. +// Long term, we need to define a mechanism to specify which flags +// are external/stable and change this function accordingly. +bool JVMFlag::is_external() const { + return is_manageable() || is_external_ext(); +} + +// Helper function for JVMFlag::print_on(). +// Fills current line up to requested position. +// Should the current position already be past the requested position, +// one separator blank is enforced. +void fill_to_pos(outputStream* st, unsigned int req_pos) { + if ((unsigned int)st->position() < req_pos) { + st->fill_to(req_pos); // need to fill with blanks to reach req_pos + } else { + st->print(" "); // enforce blank separation. Previous field too long. + } +} + +void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) { + // Don't print notproduct and develop flags in a product build. + if (is_constant_in_binary()) { + return; + } + + if (!printRanges) { + // The command line options -XX:+PrintFlags* cause this function to be called + // for each existing flag to print information pertinent to this flag. The data + // is displayed in columnar form, with the following layout: + // col1 - data type, right-justified + // col2 - name, left-justified + // col3 - ' =' double-char, leading space to align with possible '+=' + // col4 - value left-justified + // col5 - kind right-justified + // col6 - origin left-justified + // col7 - comments left-justified + // + // The column widths are fixed. They are defined such that, for most cases, + // an eye-pleasing tabular output is created. + // + // Sample output: + // bool CMSScavengeBeforeRemark = false {product} {default} + // uintx CMSScheduleRemarkEdenPenetration = 50 {product} {default} + // size_t CMSScheduleRemarkEdenSizeThreshold = 2097152 {product} {default} + // uintx CMSScheduleRemarkSamplingRatio = 5 {product} {default} + // double CMSSmallCoalSurplusPercent = 1.050000 {product} {default} + // ccstr CompileCommandFile = MyFile.cmd {product} {command line} + // ccstrlist CompileOnly = Method1 + // CompileOnly += Method2 {product} {command line} + // | | | | | | | + // | | | | | | +-- col7 + // | | | | | +-- col6 + // | | | | +-- col5 + // | | | +-- col4 + // | | +-- col3 + // | +-- col2 + // +-- col1 + + const unsigned int col_spacing = 1; + const unsigned int col1_pos = 0; + const unsigned int col1_width = 9; + const unsigned int col2_pos = col1_pos + col1_width + col_spacing; + const unsigned int col2_width = 39; + const unsigned int col3_pos = col2_pos + col2_width + col_spacing; + const unsigned int col3_width = 2; + const unsigned int col4_pos = col3_pos + col3_width + col_spacing; + const unsigned int col4_width = 30; + const unsigned int col5_pos = col4_pos + col4_width + col_spacing; + const unsigned int col5_width = 20; + const unsigned int col6_pos = col5_pos + col5_width + col_spacing; + const unsigned int col6_width = 15; + const unsigned int col7_pos = col6_pos + col6_width + col_spacing; + const unsigned int col7_width = 1; + + st->fill_to(col1_pos); + st->print("%*s", col1_width, _type); // right-justified, therefore width is required. + + fill_to_pos(st, col2_pos); + st->print("%s", _name); + + fill_to_pos(st, col3_pos); + st->print(" ="); // use " =" for proper alignment with multiline ccstr output. + + fill_to_pos(st, col4_pos); + if (is_bool()) { + st->print("%s", get_bool() ? "true" : "false"); + } else if (is_int()) { + st->print("%d", get_int()); + } else if (is_uint()) { + st->print("%u", get_uint()); + } else if (is_intx()) { + st->print(INTX_FORMAT, get_intx()); + } else if (is_uintx()) { + st->print(UINTX_FORMAT, get_uintx()); + } else if (is_uint64_t()) { + st->print(UINT64_FORMAT, get_uint64_t()); + } else if (is_size_t()) { + st->print(SIZE_FORMAT, get_size_t()); + } else if (is_double()) { + st->print("%f", get_double()); + } else if (is_ccstr()) { + // Honor characters in ccstr: print multiple lines. + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + size_t llen = pointer_delta(eol, cp, sizeof(char)); + st->print("%.*s", (int)llen, cp); + st->cr(); + cp = eol+1; + fill_to_pos(st, col2_pos); + st->print("%s", _name); + fill_to_pos(st, col3_pos); + st->print("+="); + fill_to_pos(st, col4_pos); + } + st->print("%s", cp); + } + } else { + st->print("unhandled type %s", _type); + st->cr(); + return; + } + + fill_to_pos(st, col5_pos); + print_kind(st, col5_width); + + fill_to_pos(st, col6_pos); + print_origin(st, col6_width); + +#ifndef PRODUCT + if (withComments) { + fill_to_pos(st, col7_pos); + st->print("%s", _doc); + } +#endif + st->cr(); + } else if (!is_bool() && !is_ccstr()) { + // The command line options -XX:+PrintFlags* cause this function to be called + // for each existing flag to print information pertinent to this flag. The data + // is displayed in columnar form, with the following layout: + // col1 - data type, right-justified + // col2 - name, left-justified + // col4 - range [ min ... max] + // col5 - kind right-justified + // col6 - origin left-justified + // col7 - comments left-justified + // + // The column widths are fixed. They are defined such that, for most cases, + // an eye-pleasing tabular output is created. + // + // Sample output: + // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} + // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} + // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} + // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} + // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} + // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} + // | | | | | | + // | | | | | +-- col7 + // | | | | +-- col6 + // | | | +-- col5 + // | | +-- col4 + // | +-- col2 + // +-- col1 + + const unsigned int col_spacing = 1; + const unsigned int col1_pos = 0; + const unsigned int col1_width = 9; + const unsigned int col2_pos = col1_pos + col1_width + col_spacing; + const unsigned int col2_width = 49; + const unsigned int col3_pos = col2_pos + col2_width + col_spacing; + const unsigned int col3_width = 0; + const unsigned int col4_pos = col3_pos + col3_width + col_spacing; + const unsigned int col4_width = 60; + const unsigned int col5_pos = col4_pos + col4_width + col_spacing; + const unsigned int col5_width = 35; + const unsigned int col6_pos = col5_pos + col5_width + col_spacing; + const unsigned int col6_width = 15; + const unsigned int col7_pos = col6_pos + col6_width + col_spacing; + const unsigned int col7_width = 1; + + st->fill_to(col1_pos); + st->print("%*s", col1_width, _type); // right-justified, therefore width is required. + + fill_to_pos(st, col2_pos); + st->print("%s", _name); + + fill_to_pos(st, col4_pos); + RangeStrFunc func = NULL; + if (is_int()) { + func = JVMFlag::get_int_default_range_str; + } else if (is_uint()) { + func = JVMFlag::get_uint_default_range_str; + } else if (is_intx()) { + func = JVMFlag::get_intx_default_range_str; + } else if (is_uintx()) { + func = JVMFlag::get_uintx_default_range_str; + } else if (is_uint64_t()) { + func = JVMFlag::get_uint64_t_default_range_str; + } else if (is_size_t()) { + func = JVMFlag::get_size_t_default_range_str; + } else if (is_double()) { + func = JVMFlag::get_double_default_range_str; + } else { + st->print("unhandled type %s", _type); + st->cr(); + return; + } + JVMFlagRangeList::print(st, _name, func); + + fill_to_pos(st, col5_pos); + print_kind(st, col5_width); + + fill_to_pos(st, col6_pos); + print_origin(st, col6_width); + +#ifndef PRODUCT + if (withComments) { + fill_to_pos(st, col7_pos); + st->print("%s", _doc); + } +#endif + st->cr(); + } +} + +void JVMFlag::print_kind(outputStream* st, unsigned int width) { + struct Data { + int flag; + const char* name; + }; + + Data data[] = { + { KIND_JVMCI, "JVMCI" }, + { KIND_C1, "C1" }, + { KIND_C2, "C2" }, + { KIND_ARCH, "ARCH" }, + { KIND_PLATFORM_DEPENDENT, "pd" }, + { KIND_PRODUCT, "product" }, + { KIND_MANAGEABLE, "manageable" }, + { KIND_DIAGNOSTIC, "diagnostic" }, + { KIND_EXPERIMENTAL, "experimental" }, + { KIND_COMMERCIAL, "commercial" }, + { KIND_NOT_PRODUCT, "notproduct" }, + { KIND_DEVELOP, "develop" }, + { KIND_LP64_PRODUCT, "lp64_product" }, + { KIND_READ_WRITE, "rw" }, + { -1, "" } + }; + + if ((_flags & KIND_MASK) != 0) { + bool is_first = true; + const size_t buffer_size = 64; + size_t buffer_used = 0; + char kind[buffer_size]; + + jio_snprintf(kind, buffer_size, "{"); + buffer_used++; + for (int i = 0; data[i].flag != -1; i++) { + Data d = data[i]; + if ((_flags & d.flag) != 0) { + if (is_first) { + is_first = false; + } else { + assert(buffer_used + 1 < buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); + buffer_used++; + } + size_t length = strlen(d.name); + assert(buffer_used + length < buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); + buffer_used += length; + } + } + assert(buffer_used + 2 <= buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); + st->print("%*s", width, kind); + } +} + +void JVMFlag::print_origin(outputStream* st, unsigned int width) { + int origin = _flags & VALUE_ORIGIN_MASK; + st->print("{"); + switch(origin) { + case DEFAULT: + st->print("default"); break; + case COMMAND_LINE: + st->print("command line"); break; + case ENVIRON_VAR: + st->print("environment"); break; + case CONFIG_FILE: + st->print("config file"); break; + case MANAGEMENT: + st->print("management"); break; + case ERGONOMIC: + if (_flags & ORIG_COMMAND_LINE) { + st->print("command line, "); + } + st->print("ergonomic"); break; + case ATTACH_ON_DEMAND: + st->print("attach"); break; + case INTERNAL: + st->print("internal"); break; + } + st->print("}"); +} + +void JVMFlag::print_as_flag(outputStream* st) { + if (is_bool()) { + st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); + } else if (is_int()) { + st->print("-XX:%s=%d", _name, get_int()); + } else if (is_uint()) { + st->print("-XX:%s=%u", _name, get_uint()); + } else if (is_intx()) { + st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); + } else if (is_uintx()) { + st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); + } else if (is_uint64_t()) { + st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); + } else if (is_size_t()) { + st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); + } else if (is_double()) { + st->print("-XX:%s=%f", _name, get_double()); + } else if (is_ccstr()) { + st->print("-XX:%s=", _name); + const char* cp = get_ccstr(); + if (cp != NULL) { + // Need to turn embedded '\n's back into separate arguments + // Not so efficient to print one character at a time, + // but the choice is to do the transformation to a buffer + // and print that. And this need not be efficient. + for (; *cp != '\0'; cp += 1) { + switch (*cp) { + default: + st->print("%c", *cp); + break; + case '\n': + st->print(" -XX:%s=", _name); + break; + } + } + } + } else { + ShouldNotReachHere(); + } +} + +const char* JVMFlag::flag_error_str(JVMFlag::Error error) { + switch (error) { + case JVMFlag::MISSING_NAME: return "MISSING_NAME"; + case JVMFlag::MISSING_VALUE: return "MISSING_VALUE"; + case JVMFlag::NON_WRITABLE: return "NON_WRITABLE"; + case JVMFlag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; + case JVMFlag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; + case JVMFlag::INVALID_FLAG: return "INVALID_FLAG"; + case JVMFlag::ERR_OTHER: return "ERR_OTHER"; + case JVMFlag::SUCCESS: return "SUCCESS"; + default: ShouldNotReachHere(); return "NULL"; + } +} + +// 4991491 do not "optimize out" the was_set false values: omitting them +// tickles a Microsoft compiler bug causing flagTable to be malformed + +#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT) }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DIAGNOSTIC) }, +#define RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_EXPERIMENTAL) }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_MANAGEABLE) }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_READ_WRITE) }, +#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DEVELOP) }, +#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_NOT_PRODUCT) }, + +#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_PRODUCT) }, +#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DIAGNOSTIC) }, +#define JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_EXPERIMENTAL) }, +#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DEVELOP) }, +#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_NOT_PRODUCT) }, + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_LP64_PRODUCT) }, +#else +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ +#endif // _LP64 + +#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_PRODUCT) }, +#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DIAGNOSTIC) }, +#define C1_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DEVELOP) }, +#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_NOT_PRODUCT) }, + +#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_PRODUCT) }, +#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DIAGNOSTIC) }, +#define C2_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_EXPERIMENTAL) }, +#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DEVELOP) }, +#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_NOT_PRODUCT) }, + +#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_PRODUCT) }, +#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_DIAGNOSTIC) }, +#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_EXPERIMENTAL) }, +#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_DEVELOP) }, +#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_NOT_PRODUCT) }, + +static JVMFlag flagTable[] = { + VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PRODUCT_FLAG_STRUCT, \ + RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ + RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \ + RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ + RUNTIME_MANAGEABLE_FLAG_STRUCT, \ + RUNTIME_PRODUCT_RW_FLAG_STRUCT, \ + RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) + + RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PRODUCT_FLAG_STRUCT, \ + RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ + RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ + JVMCI_PD_DEVELOP_FLAG_STRUCT, \ + JVMCI_PRODUCT_FLAG_STRUCT, \ + JVMCI_PD_PRODUCT_FLAG_STRUCT, \ + JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ + JVMCI_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // INCLUDE_JVMCI +#ifdef COMPILER1 + C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ + C1_PD_DEVELOP_FLAG_STRUCT, \ + C1_PRODUCT_FLAG_STRUCT, \ + C1_PD_PRODUCT_FLAG_STRUCT, \ + C1_DIAGNOSTIC_FLAG_STRUCT, \ + C1_PD_DIAGNOSTIC_FLAG_STRUCT, \ + C1_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // COMPILER1 +#ifdef COMPILER2 + C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \ + C2_PD_DEVELOP_FLAG_STRUCT, \ + C2_PRODUCT_FLAG_STRUCT, \ + C2_PD_PRODUCT_FLAG_STRUCT, \ + C2_DIAGNOSTIC_FLAG_STRUCT, \ + C2_PD_DIAGNOSTIC_FLAG_STRUCT, \ + C2_EXPERIMENTAL_FLAG_STRUCT, \ + C2_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // COMPILER2 + ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ + ARCH_PRODUCT_FLAG_STRUCT, \ + ARCH_DIAGNOSTIC_FLAG_STRUCT, \ + ARCH_EXPERIMENTAL_FLAG_STRUCT, \ + ARCH_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) + FLAGTABLE_EXT + {0, NULL, NULL} +}; + +JVMFlag* JVMFlag::flags = flagTable; +size_t JVMFlag::numFlags = (sizeof(flagTable) / sizeof(JVMFlag)); + +inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { + if (s_len != q_len) return false; + return memcmp(s, q, q_len) == 0; +} + +// Search the flag table for a named flag +JVMFlag* JVMFlag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { + for (JVMFlag* current = &flagTable[0]; current->_name != NULL; current++) { + if (str_equal(current->_name, current->get_name_length(), name, length)) { + // Found a matching entry. + // Don't report notproduct and develop flags in product builds. + if (current->is_constant_in_binary()) { + return (return_flag ? current : NULL); + } + // Report locked flags only if allowed. + if (!(current->is_unlocked() || current->is_unlocker())) { + if (!allow_locked) { + // disable use of locked flags, e.g. diagnostic, experimental, + // commercial... until they are explicitly unlocked + return NULL; + } + } + return current; + } + } + // JVMFlag name is not in the flag table + return NULL; +} + +// Get or compute the flag name length +size_t JVMFlag::get_name_length() { + if (_name_len == 0) { + _name_len = strlen(_name); + } + return _name_len; +} + +JVMFlag* JVMFlag::fuzzy_match(const char* name, size_t length, bool allow_locked) { + float VMOptionsFuzzyMatchSimilarity = 0.7f; + JVMFlag* match = NULL; + float score; + float max_score = -1; + + for (JVMFlag* current = &flagTable[0]; current->_name != NULL; current++) { + score = StringUtils::similarity(current->_name, strlen(current->_name), name, length); + if (score > max_score) { + max_score = score; + match = current; + } + } + + if (!(match->is_unlocked() || match->is_unlocker())) { + if (!allow_locked) { + return NULL; + } + } + + if (max_score < VMOptionsFuzzyMatchSimilarity) { + return NULL; + } + + return match; +} + +// Returns the address of the index'th element +static JVMFlag* address_of_flag(JVMFlagsWithType flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + return &JVMFlag::flags[flag]; +} + +bool JVMFlagEx::is_default(JVMFlags flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + JVMFlag* f = &JVMFlag::flags[flag]; + return f->is_default(); +} + +bool JVMFlagEx::is_ergo(JVMFlags flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + JVMFlag* f = &JVMFlag::flags[flag]; + return f->is_ergonomic(); +} + +bool JVMFlagEx::is_cmdline(JVMFlags flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + JVMFlag* f = &JVMFlag::flags[flag]; + return f->is_command_line(); +} + +bool JVMFlag::wasSetOnCmdline(const char* name, bool* value) { + JVMFlag* result = JVMFlag::find_flag((char*)name, strlen(name)); + if (result == NULL) return false; + *value = result->is_command_line(); + return true; +} + +void JVMFlagEx::setOnCmdLine(JVMFlagsWithType flag) { + JVMFlag* faddr = address_of_flag(flag); + assert(faddr != NULL, "Unknown flag"); + faddr->set_command_line(); +} + +template +static void trace_flag_changed(const char* name, const T old_value, const T new_value, const JVMFlag::Flags origin) { + E e; + e.set_name(name); + e.set_oldValue(old_value); + e.set_newValue(new_value); + e.set_origin(origin); + e.commit(); +} + +static JVMFlag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_bool(new_value, verbose); + } + return status; +} + +JVMFlag::Error JVMFlag::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_bool()) return JVMFlag::WRONG_FORMAT; + *value = result->get_bool(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::boolAtPut(JVMFlag* flag, bool* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_bool()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_bool(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + bool old_value = flag->get_bool(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_bool(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::boolAtPut(const char* name, size_t len, bool* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return boolAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); + return JVMFlag::boolAtPut(faddr, &value, origin); +} + +static JVMFlag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_int(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_int(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_int()) return JVMFlag::WRONG_FORMAT; + *value = result->get_int(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_int()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_int(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + int old_value = flag->get_int(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_int(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::intAtPut(const char* name, size_t len, int* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return intAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_int(), "wrong flag type"); + return JVMFlag::intAtPut(faddr, &value, origin); +} + +static JVMFlag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uint(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uint(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_uint()) return JVMFlag::WRONG_FORMAT; + *value = result->get_uint(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_uint()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_uint(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + uint old_value = flag->get_uint(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uint(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::uintAtPut(const char* name, size_t len, uint* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return uintAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type"); + return JVMFlag::uintAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_intx()) return JVMFlag::WRONG_FORMAT; + *value = result->get_intx(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_intx(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_intx(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_intx()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_intx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + intx old_value = flag->get_intx(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_intx(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::intxAtPut(const char* name, size_t len, intx* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return intxAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); + return JVMFlag::intxAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_uintx()) return JVMFlag::WRONG_FORMAT; + *value = result->get_uintx(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uintx(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uintx(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_uintx()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_uintx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + uintx old_value = flag->get_uintx(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uintx(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::uintxAtPut(const char* name, size_t len, uintx* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return uintxAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); + return JVMFlag::uintxAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_uint64_t()) return JVMFlag::WRONG_FORMAT; + *value = result->get_uint64_t(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uint64_t(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uint64_t(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_uint64_t()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + uint64_t old_value = flag->get_uint64_t(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uint64_t(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::uint64_tAtPut(const char* name, size_t len, uint64_t* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return uint64_tAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); + return JVMFlag::uint64_tAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_size_t()) return JVMFlag::WRONG_FORMAT; + *value = result->get_size_t(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_size_t(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_size_t(new_value, verbose); + } + } + return status; +} + + +JVMFlag::Error JVMFlag::size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_size_t()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_size_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + size_t old_value = flag->get_size_t(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_size_t(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::size_tAtPut(const char* name, size_t len, size_t* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return size_tAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); + return JVMFlag::size_tAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_double()) return JVMFlag::WRONG_FORMAT; + *value = result->get_double(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_double(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_double(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_double()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_double(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + double old_value = flag->get_double(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_double(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::doubleAtPut(const char* name, size_t len, double* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return doubleAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); + return JVMFlag::doubleAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_ccstr()) return JVMFlag::WRONG_FORMAT; + *value = result->get_ccstr(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::ccstrAtPut(const char* name, size_t len, ccstr* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_ccstr()) return JVMFlag::WRONG_FORMAT; + ccstr old_value = result->get_ccstr(); + trace_flag_changed(name, old_value, *value, origin); + char* new_value = NULL; + if (*value != NULL) { + new_value = os::strdup_check_oom(*value); + } + JVMFlag::Error check = result->set_ccstr(new_value); + if (result->is_default() && old_value != NULL) { + // Prior value is NOT heap allocated, but was a literal constant. + old_value = os::strdup_check_oom(old_value); + } + *value = old_value; + result->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlagEx::ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); + ccstr old_value = faddr->get_ccstr(); + trace_flag_changed(faddr->_name, old_value, value, origin); + char* new_value = os::strdup_check_oom(value); + JVMFlag::Error check = faddr->set_ccstr(new_value); + if (!faddr->is_default() && old_value != NULL) { + // Prior value is heap allocated so free it. + FREE_C_HEAP_ARRAY(char, old_value); + } + faddr->set_origin(origin); + return check; +} + +extern "C" { + static int compare_flags(const void* void_a, const void* void_b) { + return strcmp((*((JVMFlag**) void_a))->_name, (*((JVMFlag**) void_b))->_name); + } +} + +void JVMFlag::printSetFlags(outputStream* out) { + // Print which flags were set on the command line + // note: this method is called before the thread structure is in place + // which means resource allocation cannot be used. + + // The last entry is the null entry. + const size_t length = JVMFlag::numFlags - 1; + + // Sort + JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; + } + qsort(array, length, sizeof(JVMFlag*), compare_flags); + + // Print + for (size_t i = 0; i < length; i++) { + if (array[i]->get_origin() /* naked field! */) { + array[i]->print_as_flag(out); + out->print(" "); + } + } + out->cr(); + FREE_C_HEAP_ARRAY(JVMFlag*, array); +} + +#ifndef PRODUCT + +void JVMFlag::verify() { + assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); +} + +#endif // PRODUCT + +void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges) { + // Print the flags sorted by name + // note: this method is called before the thread structure is in place + // which means resource allocation cannot be used. + + // The last entry is the null entry. + const size_t length = JVMFlag::numFlags - 1; + + // Sort + JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; + } + qsort(array, length, sizeof(JVMFlag*), compare_flags); + + // Print + if (!printRanges) { + out->print_cr("[Global flags]"); + } else { + out->print_cr("[Global flags ranges]"); + } + + for (size_t i = 0; i < length; i++) { + if (array[i]->is_unlocked()) { + array[i]->print_on(out, withComments, printRanges); + } + } + FREE_C_HEAP_ARRAY(JVMFlag*, array); +} + diff --git a/src/hotspot/share/runtime/flags/jvmFlag.hpp b/src/hotspot/share/runtime/flags/jvmFlag.hpp new file mode 100644 index 00000000000..e8c8210bd06 --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlag.hpp @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP +#define SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// function type that will construct default range string +typedef const char* (*RangeStrFunc)(void); + +struct JVMFlag { + enum Flags { + // latest value origin + DEFAULT = 0, + COMMAND_LINE = 1, + ENVIRON_VAR = 2, + CONFIG_FILE = 3, + MANAGEMENT = 4, + ERGONOMIC = 5, + ATTACH_ON_DEMAND = 6, + INTERNAL = 7, + + LAST_VALUE_ORIGIN = INTERNAL, + VALUE_ORIGIN_BITS = 4, + VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), + + // flag kind + KIND_PRODUCT = 1 << 4, + KIND_MANAGEABLE = 1 << 5, + KIND_DIAGNOSTIC = 1 << 6, + KIND_EXPERIMENTAL = 1 << 7, + KIND_NOT_PRODUCT = 1 << 8, + KIND_DEVELOP = 1 << 9, + KIND_PLATFORM_DEPENDENT = 1 << 10, + KIND_READ_WRITE = 1 << 11, + KIND_C1 = 1 << 12, + KIND_C2 = 1 << 13, + KIND_ARCH = 1 << 14, + KIND_LP64_PRODUCT = 1 << 15, + KIND_COMMERCIAL = 1 << 16, + KIND_JVMCI = 1 << 17, + + // set this bit if the flag was set on the command line + ORIG_COMMAND_LINE = 1 << 18, + + KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) + }; + + enum Error { + // no error + SUCCESS = 0, + // flag name is missing + MISSING_NAME, + // flag value is missing + MISSING_VALUE, + // error parsing the textual form of the value + WRONG_FORMAT, + // flag is not writable + NON_WRITABLE, + // flag value is outside of its bounds + OUT_OF_BOUNDS, + // flag value violates its constraint + VIOLATES_CONSTRAINT, + // there is no flag with the given name + INVALID_FLAG, + // the flag can only be set only on command line during invocation of the VM + COMMAND_LINE_ONLY, + // the flag may only be set once + SET_ONLY_ONCE, + // the flag is not writable in this combination of product/debug build + CONSTANT, + // other, unspecified error related to setting the flag + ERR_OTHER + }; + + enum MsgType { + NONE = 0, + DIAGNOSTIC_FLAG_BUT_LOCKED, + EXPERIMENTAL_FLAG_BUT_LOCKED, + DEVELOPER_FLAG_BUT_PRODUCT_BUILD, + NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD, + COMMERCIAL_FLAG_BUT_DISABLED, + COMMERCIAL_FLAG_BUT_LOCKED + }; + + const char* _type; + const char* _name; + void* _addr; + NOT_PRODUCT(const char* _doc;) + Flags _flags; + size_t _name_len; + + // points to all Flags static array + static JVMFlag* flags; + + // number of flags + static size_t numFlags; + + static JVMFlag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); }; + static JVMFlag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); + static JVMFlag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); + + static const char* get_int_default_range_str(); + static const char* get_uint_default_range_str(); + static const char* get_intx_default_range_str(); + static const char* get_uintx_default_range_str(); + static const char* get_uint64_t_default_range_str(); + static const char* get_size_t_default_range_str(); + static const char* get_double_default_range_str(); + + JVMFlag::Error check_writable(bool changed); + + bool is_bool() const; + bool get_bool() const; + JVMFlag::Error set_bool(bool value); + + bool is_int() const; + int get_int() const; + JVMFlag::Error set_int(int value); + + bool is_uint() const; + uint get_uint() const; + JVMFlag::Error set_uint(uint value); + + bool is_intx() const; + intx get_intx() const; + JVMFlag::Error set_intx(intx value); + + bool is_uintx() const; + uintx get_uintx() const; + JVMFlag::Error set_uintx(uintx value); + + bool is_uint64_t() const; + uint64_t get_uint64_t() const; + JVMFlag::Error set_uint64_t(uint64_t value); + + bool is_size_t() const; + size_t get_size_t() const; + JVMFlag::Error set_size_t(size_t value); + + bool is_double() const; + double get_double() const; + JVMFlag::Error set_double(double value); + + bool is_ccstr() const; + bool ccstr_accumulates() const; + ccstr get_ccstr() const; + JVMFlag::Error set_ccstr(ccstr value); + + Flags get_origin(); + void set_origin(Flags origin); + + size_t get_name_length(); + + bool is_default(); + bool is_ergonomic(); + bool is_command_line(); + void set_command_line(); + + bool is_product() const; + bool is_manageable() const; + bool is_diagnostic() const; + bool is_experimental() const; + bool is_notproduct() const; + bool is_develop() const; + bool is_read_write() const; + bool is_commercial() const; + + bool is_constant_in_binary() const; + + bool is_unlocker() const; + bool is_unlocked() const; + bool is_writeable() const; + bool is_external() const; + + bool is_unlocker_ext() const; + bool is_unlocked_ext() const; + bool is_writeable_ext() const; + bool is_external_ext() const; + + void clear_diagnostic(); + + JVMFlag::MsgType get_locked_message(char*, int) const; + JVMFlag::MsgType get_locked_message_ext(char*, int) const; + + // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges + void print_on(outputStream* st, bool withComments = false, bool printRanges = false); + void print_kind(outputStream* st, unsigned int width); + void print_origin(outputStream* st, unsigned int width); + void print_as_flag(outputStream* st); + + static const char* flag_error_str(JVMFlag::Error error); + +public: + static JVMFlag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error boolAtPut(JVMFlag* flag, bool* value, JVMFlag::Flags origin); + static JVMFlag::Error boolAtPut(const char* name, size_t len, bool* value, JVMFlag::Flags origin); + static JVMFlag::Error boolAtPut(const char* name, bool* value, JVMFlag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origin); + static JVMFlag::Error intAtPut(const char* name, size_t len, int* value, JVMFlag::Flags origin); + static JVMFlag::Error intAtPut(const char* name, int* value, JVMFlag::Flags origin) { return intAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags origin); + static JVMFlag::Error uintAtPut(const char* name, size_t len, uint* value, JVMFlag::Flags origin); + static JVMFlag::Error uintAtPut(const char* name, uint* value, JVMFlag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags origin); + static JVMFlag::Error intxAtPut(const char* name, size_t len, intx* value, JVMFlag::Flags origin); + static JVMFlag::Error intxAtPut(const char* name, intx* value, JVMFlag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags origin); + static JVMFlag::Error uintxAtPut(const char* name, size_t len, uintx* value, JVMFlag::Flags origin); + static JVMFlag::Error uintxAtPut(const char* name, uintx* value, JVMFlag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin); + static JVMFlag::Error size_tAtPut(const char* name, size_t len, size_t* value, JVMFlag::Flags origin); + static JVMFlag::Error size_tAtPut(const char* name, size_t* value, JVMFlag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::Flags origin); + static JVMFlag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, JVMFlag::Flags origin); + static JVMFlag::Error uint64_tAtPut(const char* name, uint64_t* value, JVMFlag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags origin); + static JVMFlag::Error doubleAtPut(const char* name, size_t len, double* value, JVMFlag::Flags origin); + static JVMFlag::Error doubleAtPut(const char* name, double* value, JVMFlag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); } + // Contract: JVMFlag will make private copy of the incoming value. + // Outgoing value is always malloc-ed, and caller MUST call free. + static JVMFlag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, JVMFlag::Flags origin); + static JVMFlag::Error ccstrAtPut(const char* name, ccstr* value, JVMFlag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } + + // Returns false if name is not a command line flag. + static bool wasSetOnCmdline(const char* name, bool* value); + static void printSetFlags(outputStream* out); + + // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges + static void printFlags(outputStream* out, bool withComments, bool printRanges = false); + + static void verify() PRODUCT_RETURN; +}; + +#endif // SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp similarity index 58% rename from src/hotspot/share/runtime/commandLineFlagConstraintList.cpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp index c900c2e4e1a..a0832397585 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp @@ -25,11 +25,12 @@ #include "precompiled.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" -#include "gc/shared/commandLineFlagConstraintsGC.hpp" +#include "gc/shared/jvmFlagConstraintsGC.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagConstraintsCompiler.hpp" -#include "runtime/commandLineFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagConstraintsCompiler.hpp" +#include "runtime/flags/jvmFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" #ifdef COMPILER1 @@ -39,162 +40,161 @@ #include "opto/c2_globals.hpp" #endif - -class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_bool _constraint; +class JVMFlagConstraint_bool : public JVMFlagConstraint { + JVMFlagConstraintFunc_bool _constraint; const bool* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_bool(const char* name, const bool* ptr, - CommandLineFlagConstraintFunc_bool func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_bool(const char* name, const bool* ptr, + JVMFlagConstraintFunc_bool func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { bool value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_bool(bool value, bool verbose) { + JVMFlag::Error apply_bool(bool value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_int : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_int _constraint; +class JVMFlagConstraint_int : public JVMFlagConstraint { + JVMFlagConstraintFunc_int _constraint; const int* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_int(const char* name, const int* ptr, - CommandLineFlagConstraintFunc_int func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_int(const char* name, const int* ptr, + JVMFlagConstraintFunc_int func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { int value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_int(int value, bool verbose) { + JVMFlag::Error apply_int(int value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_intx : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_intx _constraint; +class JVMFlagConstraint_intx : public JVMFlagConstraint { + JVMFlagConstraintFunc_intx _constraint; const intx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_intx(const char* name, const intx* ptr, - CommandLineFlagConstraintFunc_intx func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_intx(const char* name, const intx* ptr, + JVMFlagConstraintFunc_intx func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { intx value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_intx(intx value, bool verbose) { + JVMFlag::Error apply_intx(intx value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_uint : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_uint _constraint; +class JVMFlagConstraint_uint : public JVMFlagConstraint { + JVMFlagConstraintFunc_uint _constraint; const uint* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uint(const char* name, const uint* ptr, - CommandLineFlagConstraintFunc_uint func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_uint(const char* name, const uint* ptr, + JVMFlagConstraintFunc_uint func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { uint value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_uint(uint value, bool verbose) { + JVMFlag::Error apply_uint(uint value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_uintx : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_uintx _constraint; +class JVMFlagConstraint_uintx : public JVMFlagConstraint { + JVMFlagConstraintFunc_uintx _constraint; const uintx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uintx(const char* name, const uintx* ptr, - CommandLineFlagConstraintFunc_uintx func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_uintx(const char* name, const uintx* ptr, + JVMFlagConstraintFunc_uintx func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { uintx value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_uintx(uintx value, bool verbose) { + JVMFlag::Error apply_uintx(uintx value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_uint64_t : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_uint64_t _constraint; +class JVMFlagConstraint_uint64_t : public JVMFlagConstraint { + JVMFlagConstraintFunc_uint64_t _constraint; const uint64_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uint64_t(const char* name, const uint64_t* ptr, - CommandLineFlagConstraintFunc_uint64_t func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_uint64_t(const char* name, const uint64_t* ptr, + JVMFlagConstraintFunc_uint64_t func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { uint64_t value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_uint64_t(uint64_t value, bool verbose) { + JVMFlag::Error apply_uint64_t(uint64_t value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_size_t : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_size_t _constraint; +class JVMFlagConstraint_size_t : public JVMFlagConstraint { + JVMFlagConstraintFunc_size_t _constraint; const size_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_size_t(const char* name, const size_t* ptr, - CommandLineFlagConstraintFunc_size_t func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_size_t(const char* name, const size_t* ptr, + JVMFlagConstraintFunc_size_t func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { size_t value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_size_t(size_t value, bool verbose) { + JVMFlag::Error apply_size_t(size_t value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_double : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_double _constraint; +class JVMFlagConstraint_double : public JVMFlagConstraint { + JVMFlagConstraintFunc_double _constraint; const double* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_double(const char* name, const double* ptr, - CommandLineFlagConstraintFunc_double func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_double(const char* name, const double* ptr, + JVMFlagConstraintFunc_double func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { double value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_double(double value, bool verbose) { + JVMFlag::Error apply_double(double value, bool verbose) { return _constraint(value, verbose); } }; @@ -214,30 +214,30 @@ void emit_constraint_uint64_t(const char* /*name*/, const uint64_t* /*value*/) void emit_constraint_size_t(const char* /*name*/, const size_t* /*value*/) { /* NOP */ } void emit_constraint_double(const char* /*name*/, const double* /*value*/) { /* NOP */ } -// CommandLineFlagConstraint emitting code functions if function argument is provided -void emit_constraint_bool(const char* name, const bool* ptr, CommandLineFlagConstraintFunc_bool func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_bool(name, ptr, func, type)); +// JVMFlagConstraint emitting code functions if function argument is provided +void emit_constraint_bool(const char* name, const bool* ptr, JVMFlagConstraintFunc_bool func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_bool(name, ptr, func, type)); } -void emit_constraint_int(const char* name, const int* ptr, CommandLineFlagConstraintFunc_int func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_int(name, ptr, func, type)); +void emit_constraint_int(const char* name, const int* ptr, JVMFlagConstraintFunc_int func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_int(name, ptr, func, type)); } -void emit_constraint_intx(const char* name, const intx* ptr, CommandLineFlagConstraintFunc_intx func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_intx(name, ptr, func, type)); +void emit_constraint_intx(const char* name, const intx* ptr, JVMFlagConstraintFunc_intx func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_intx(name, ptr, func, type)); } -void emit_constraint_uint(const char* name, const uint* ptr, CommandLineFlagConstraintFunc_uint func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint(name, ptr, func, type)); +void emit_constraint_uint(const char* name, const uint* ptr, JVMFlagConstraintFunc_uint func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_uint(name, ptr, func, type)); } -void emit_constraint_uintx(const char* name, const uintx* ptr, CommandLineFlagConstraintFunc_uintx func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uintx(name, ptr, func, type)); +void emit_constraint_uintx(const char* name, const uintx* ptr, JVMFlagConstraintFunc_uintx func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_uintx(name, ptr, func, type)); } -void emit_constraint_uint64_t(const char* name, const uint64_t* ptr, CommandLineFlagConstraintFunc_uint64_t func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint64_t(name, ptr, func, type)); +void emit_constraint_uint64_t(const char* name, const uint64_t* ptr, JVMFlagConstraintFunc_uint64_t func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_uint64_t(name, ptr, func, type)); } -void emit_constraint_size_t(const char* name, const size_t* ptr, CommandLineFlagConstraintFunc_size_t func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_size_t(name, ptr, func, type)); +void emit_constraint_size_t(const char* name, const size_t* ptr, JVMFlagConstraintFunc_size_t func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_size_t(name, ptr, func, type)); } -void emit_constraint_double(const char* name, const double* ptr, CommandLineFlagConstraintFunc_double func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_double(name, ptr, func, type)); +void emit_constraint_double(const char* name, const double* ptr, JVMFlagConstraintFunc_double func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_double(name, ptr, func, type)); } // Generate code to call emit_constraint_xxx function @@ -265,16 +265,16 @@ void emit_constraint_double(const char* name, const double* ptr, CommandLineFlag #endif // Generate func argument to pass into emit_constraint_xxx functions -#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type +#define EMIT_CONSTRAINT_CHECK(func, type) , func, JVMFlagConstraint::type // the "name" argument must be a string literal #define INITIAL_CONSTRAINTS_SIZE 72 -GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; -CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; +GrowableArray* JVMFlagConstraintList::_constraints = NULL; +JVMFlagConstraint::ConstraintType JVMFlagConstraintList::_validating_type = JVMFlagConstraint::AtParse; // Check the ranges of all flags that have them or print them out and exit if requested -void CommandLineFlagConstraintList::init(void) { - _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); +void JVMFlagConstraintList::init(void) { + _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); emit_constraint_no(NULL VM_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, @@ -331,10 +331,10 @@ void CommandLineFlagConstraintList::init(void) { #endif // COMPILER2 } -CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) { - CommandLineFlagConstraint* found = NULL; +JVMFlagConstraint* JVMFlagConstraintList::find(const char* name) { + JVMFlagConstraint* found = NULL; for (int i=0; iname(), name) == 0) { found = constraint; break; @@ -344,9 +344,9 @@ CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) } // Find constraints by name and return only if found constraint's type is equal or lower than current validating type. -CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(const char* name) { - CommandLineFlagConstraint* found = NULL; - CommandLineFlagConstraint* constraint = find(name); +JVMFlagConstraint* JVMFlagConstraintList::find_if_needs_check(const char* name) { + JVMFlagConstraint* found = NULL; + JVMFlagConstraint* constraint = find(name); if (constraint && (constraint->type() <= _validating_type)) { found = constraint; } @@ -354,15 +354,15 @@ CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(co } // Check constraints for specific constraint type. -bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { +bool JVMFlagConstraintList::check_constraints(JVMFlagConstraint::ConstraintType type) { guarantee(type > _validating_type, "Constraint check is out of order."); _validating_type = type; bool status = true; for (int i=0; itype()) continue; - if (constraint->apply(true) != Flag::SUCCESS) status = false; + if (constraint->apply(true) != JVMFlag::SUCCESS) status = false; } return status; } diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp new file mode 100644 index 00000000000..9c27f1db955 --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP +#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP + +#include "runtime/flags/jvmFlag.hpp" +#include "utilities/growableArray.hpp" + +/* + * Here we have a mechanism for extracting constraints (as custom functions) for flags, + * which otherwise can not be expressed via simple range check, specified in flag macro tables. + * + * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change. + * + * See runtime "runtime/flags/jvmFlagConstraintsCompiler.hpp", + * "runtime/flags/jvmFlagConstraintsGC.hpp" and + * "runtime/flags/jvmFlagConstraintsRuntime.hpp" for the functions themselves. + */ + +typedef JVMFlag::Error (*JVMFlagConstraintFunc_bool)(bool value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_int)(int value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_intx)(intx value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint)(uint value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_uintx)(uintx value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_size_t)(size_t value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_double)(double value, bool verbose); + +class JVMFlagConstraint : public CHeapObj { +public: + // During VM initialization, constraint validation will be done order of ConstraintType. + enum ConstraintType { + // Will be validated during argument processing (Arguments::parse_argument). + AtParse = 0, + // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). + AfterErgo = 1, + // Will be validated inside universe_init(), right after Metaspace::global_initialize(). + AfterMemoryInit = 2 + }; + +private: + const char* _name; + ConstraintType _validate_type; + +public: + // the "name" argument must be a string literal + JVMFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; + ~JVMFlagConstraint() {}; + const char* name() const { return _name; } + ConstraintType type() const { return _validate_type; } + virtual JVMFlag::Error apply(bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; +}; + +class JVMFlagConstraintList : public AllStatic { +private: + static GrowableArray* _constraints; + // Latest constraint validation type. + static JVMFlagConstraint::ConstraintType _validating_type; +public: + static void init(); + static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } + static JVMFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } + static JVMFlagConstraint* find(const char* name); + static JVMFlagConstraint* find_if_needs_check(const char* name); + static void add(JVMFlagConstraint* constraint) { _constraints->append(constraint); } + // True if 'AfterErgo' or later constraint functions are validated. + static bool validated_after_ergo() { return _validating_type >= JVMFlagConstraint::AfterErgo; }; + static bool check_constraints(JVMFlagConstraint::ConstraintType type); +}; + +#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp similarity index 80% rename from src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 13d8498aa5e..3055dfcd026 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -29,21 +29,22 @@ #include "runtime/os.hpp" #include "interpreter/invocationCounter.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintsCompiler.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintsCompiler.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "utilities/defaultStream.hpp" -Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose) { if ((value <= 1) && (Arguments::mode() == Arguments::_comp || Arguments::mode() == Arguments::_mixed)) { CommandLineError::print(verbose, "AliasLevel (" INTX_FORMAT ") is not " "compatible with -Xcomp or -Xmixed\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -62,7 +63,7 @@ Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { * 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result, * the minimum number of compiler threads is 2. */ -Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; #if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI // case 1 @@ -85,37 +86,37 @@ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { "CICompilerCount (" INTX_FORMAT ") must be " "at least %d \n", value, min_number_of_compiler_threads); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { if (value < 0 || value > 512) { CommandLineError::print(verbose, "AllocatePrefetchDistance (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", AllocatePrefetchDistance, 512); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { if (AllocatePrefetchStyle == 3) { if (value % wordSize != 0) { CommandLineError::print(verbose, "AllocatePrefetchStepSize (" INTX_FORMAT ") must be multiple of %d\n", value, wordSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { intx max_value = max_intx; #if defined(SPARC) max_value = 1; @@ -126,26 +127,26 @@ Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "AllocatePrefetchInstr (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", value, max_value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { if (value < 0 || value > INT_MAX >> InvocationCounter::count_shift) { CommandLineError::print(verbose, "CompileThreshold (" INTX_FORMAT ") " "must be between 0 and %d\n", value, INT_MAX >> InvocationCounter::count_shift); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { +JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { int backward_branch_limit; if (ProfileInterpreter) { if (OnStackReplacePercentage < InterpreterProfilePercentage) { @@ -153,7 +154,7 @@ Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { "OnStackReplacePercentage (" INTX_FORMAT ") must be " "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", OnStackReplacePercentage, InterpreterProfilePercentage); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } backward_branch_limit = ((CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100) @@ -167,14 +168,14 @@ Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { "CompileThreshold, InterpreterProfilePercentage, and/or OnStackReplacePercentage\n", (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100, INT_MAX >> InvocationCounter::count_shift); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } else { if (OnStackReplacePercentage < 0 ) { CommandLineError::print(verbose, "OnStackReplacePercentage (" INTX_FORMAT ") must be " "non-negative\n", OnStackReplacePercentage); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } backward_branch_limit = ((CompileThreshold * OnStackReplacePercentage) / 100) @@ -187,20 +188,20 @@ Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { "CompileThreshold and/or OnStackReplacePercentage\n", (CompileThreshold * OnStackReplacePercentage) / 100, INT_MAX >> InvocationCounter::count_shift); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) { CommandLineError::print(verbose, "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ") " "to align entry points\n", CodeCacheSegmentSize, CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (CodeCacheSegmentSize < sizeof(jdouble)) { @@ -208,7 +209,7 @@ Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " "at least " SIZE_FORMAT " to align constants\n", CodeCacheSegmentSize, sizeof(jdouble)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #ifdef COMPILER2 @@ -218,14 +219,14 @@ Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ") " "to align inner loops\n", CodeCacheSegmentSize, OptoLoopAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { #ifdef SOLARIS if ((value < MinimumPriority || value > MaximumPriority) && (value != -1) && (value != -FXCriticalPriority)) { @@ -234,20 +235,20 @@ Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { "between %d and %d inclusively or -1 (means no change) " "or %d (special value for critical thread class/priority)\n", value, MinimumPriority, MaximumPriority, -FXCriticalPriority); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { #ifdef SPARC if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { CommandLineError::print(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "multiple of NOP size\n", CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif @@ -255,7 +256,7 @@ Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (CodeEntryAlignment < 16) { @@ -263,19 +264,19 @@ Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { "CodeEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", CodeEntryAlignment, 16); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { +JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "OptoLoopAlignment (" INTX_FORMAT ") " "must be a power of two\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // Relevant on ppc, s390, sparc. Will be optimized where @@ -285,64 +286,64 @@ Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { "OptoLoopAlignment (" INTX_FORMAT ") must be " "multiple of NOP size (%d)\n", value, relocInfo::addr_unit()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { if (value >= 4032) { CommandLineError::print(verbose, "ArraycopyDstPrefetchDistance (" UINTX_FORMAT ") must be" "between 0 and 4031\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { if (value >= 4032) { CommandLineError::print(verbose, "ArraycopySrcPrefetchDistance (" UINTX_FORMAT ") must be" "between 0 and 4031\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { for (int i = 0; i < 3; i++) { if (value % 10 > 2) { CommandLineError::print(verbose, "Invalid value (" UINTX_FORMAT ") " "in TypeProfileLevel at position %d\n", value, i); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } value = value / 10; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { +JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { if (value % BytesPerLong != 0) { - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } #ifdef COMPILER2 -Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { +JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { if (InteriorEntryAlignment > CodeEntryAlignment) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", InteriorEntryAlignment, CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #ifdef SPARC @@ -350,7 +351,7 @@ Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "multiple of NOP size\n"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif @@ -358,7 +359,7 @@ Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", InteriorEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } int minimum_alignment = 16; @@ -373,26 +374,26 @@ Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { "InteriorEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", InteriorEntryAlignment, minimum_alignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { +JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { if (value < MaxNodeLimit * 2 / 100 || value > MaxNodeLimit * 40 / 100) { CommandLineError::print(verbose, "NodeLimitFudgeFactor must be between 2%% and 40%% " "of MaxNodeLimit (" INTX_FORMAT ")\n", MaxNodeLimit); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } #endif // COMPILER2 -Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { +JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { #if INCLUDE_RTM_OPT if (UseRTMLocking && !is_power_of_2(RTMTotalCountIncrRate)) { CommandLineError::print(verbose, @@ -403,5 +404,5 @@ Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp new file mode 100644 index 00000000000..f18b1269ed1 --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP +#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP + +#include "runtime/flags/jvmFlag.hpp" + +/* + * Here we have compiler arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose); + +JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); + +JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); + +JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose); + +JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); + +JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); + +JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose); + +#ifdef COMPILER2 +JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); + +JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); +#endif + +JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose); + +#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp similarity index 77% rename from src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp index 55483983094..fdcb9bb193a 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp @@ -24,20 +24,21 @@ #include "precompiled.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintsRuntime.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/task.hpp" #include "utilities/defaultStream.hpp" -Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { +JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // In case page size is very small. if (value >= (intx)os::vm_page_size()) { @@ -45,99 +46,99 @@ Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "less than page size (" INTX_FORMAT ")\n", value, (intx)os::vm_page_size()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } // Need to enforce the padding not to break the existing field alignments. // It is sufficient to check against the largest type size. -Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { +JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { if ((value % BytesPerLong) != 0) { CommandLineError::print(verbose, "ContendedPaddingWidth (" INTX_FORMAT ") must be " "a multiple of %d\n", value, BytesPerLong); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { if (value > BiasedLockingBulkRevokeThreshold) { CommandLineError::print(verbose, "BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ") must be " "less than or equal to BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRevokeThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran) != 0) { CommandLineError::print(verbose, "BiasedLockingStartupDelay (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", value, PeriodicTask::interval_gran); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { if (value < BiasedLockingBulkRebiasThreshold) { CommandLineError::print(verbose, "BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ") must be " "greater than or equal to BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRebiasThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else if ((double)value/(double)BiasedLockingDecayTime > 0.1) { CommandLineError::print(verbose, "The ratio of BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " "less than or equal to 0.1\n", value, BiasedLockingBulkRebiasThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { if (BiasedLockingBulkRebiasThreshold/(double)value > 0.1) { CommandLineError::print(verbose, "The ratio of BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " "less than or equal to 0.1\n", BiasedLockingBulkRebiasThreshold, value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { +JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran != 0)) { CommandLineError::print(verbose, "PerfDataSamplingInterval (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", value, PeriodicTask::interval_gran); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { +JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { if (value) { if (!SafepointMechanism::supports_thread_local_poll()) { CommandLineError::print(verbose, "ThreadLocalHandshakes not yet supported on this platform\n"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp similarity index 60% rename from src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp index 52452846df2..8763b83fd37 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp @@ -22,11 +22,10 @@ * */ -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP +#ifndef SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP +#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" +#include "runtime/flags/jvmFlag.hpp" /* * Here we have runtime arguments constraints functions, which are called automatically @@ -34,18 +33,18 @@ * an appropriate error value. */ -Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); +JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); -Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); +JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); -Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); -Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); -Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); -Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); -Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); +JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); -Flag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose); +JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose); -#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */ +#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagRangeList.cpp b/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp similarity index 75% rename from src/hotspot/share/runtime/commandLineFlagRangeList.cpp rename to src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp index a6973fc12cd..97b074e59b9 100644 --- a/src/hotspot/share/runtime/commandLineFlagRangeList.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp @@ -29,8 +29,9 @@ #include "gc/shared/referenceProcessor.hpp" #include "oops/markOop.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" @@ -46,29 +47,29 @@ void CommandLineError::print(bool verbose, const char* msg, ...) { } } -class CommandLineFlagRange_int : public CommandLineFlagRange { +class JVMFlagRange_int : public JVMFlagRange { int _min; int _max; const int* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_int(const char* name, const int* ptr, int min, int max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_int(const char* name, const int* ptr, int min, int max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_int(*_ptr, verbose); } - Flag::Error check_int(int value, bool verbose = true) { + JVMFlag::Error check_int(int value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "int %s=%d is outside the allowed range " "[ %d ... %d ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -77,28 +78,28 @@ public: } }; -class CommandLineFlagRange_intx : public CommandLineFlagRange { +class JVMFlagRange_intx : public JVMFlagRange { intx _min; intx _max; const intx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_intx(const char* name, const intx* ptr, intx min, intx max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_intx(const char* name, const intx* ptr, intx min, intx max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_intx(*_ptr, verbose); } - Flag::Error check_intx(intx value, bool verbose = true) { + JVMFlag::Error check_intx(intx value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "intx %s=" INTX_FORMAT " is outside the allowed range " "[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -107,29 +108,29 @@ public: } }; -class CommandLineFlagRange_uint : public CommandLineFlagRange { +class JVMFlagRange_uint : public JVMFlagRange { uint _min; uint _max; const uint* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_uint(const char* name, const uint* ptr, uint min, uint max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_uint(const char* name, const uint* ptr, uint min, uint max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_uint(*_ptr, verbose); } - Flag::Error check_uint(uint value, bool verbose = true) { + JVMFlag::Error check_uint(uint value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uint %s=%u is outside the allowed range " "[ %u ... %u ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -138,29 +139,29 @@ public: } }; -class CommandLineFlagRange_uintx : public CommandLineFlagRange { +class JVMFlagRange_uintx : public JVMFlagRange { uintx _min; uintx _max; const uintx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_uintx(const char* name, const uintx* ptr, uintx min, uintx max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_uintx(const char* name, const uintx* ptr, uintx min, uintx max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_uintx(*_ptr, verbose); } - Flag::Error check_uintx(uintx value, bool verbose = true) { + JVMFlag::Error check_uintx(uintx value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uintx %s=" UINTX_FORMAT " is outside the allowed range " "[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -169,29 +170,29 @@ public: } }; -class CommandLineFlagRange_uint64_t : public CommandLineFlagRange { +class JVMFlagRange_uint64_t : public JVMFlagRange { uint64_t _min; uint64_t _max; const uint64_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_uint64_t(*_ptr, verbose); } - Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { + JVMFlag::Error check_uint64_t(uint64_t value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uint64_t %s=" UINT64_FORMAT " is outside the allowed range " "[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -200,29 +201,29 @@ public: } }; -class CommandLineFlagRange_size_t : public CommandLineFlagRange { +class JVMFlagRange_size_t : public JVMFlagRange { size_t _min; size_t _max; const size_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_size_t(const char* name, const size_t* ptr, size_t min, size_t max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_size_t(const char* name, const size_t* ptr, size_t min, size_t max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_size_t(*_ptr, verbose); } - Flag::Error check_size_t(size_t value, bool verbose = true) { + JVMFlag::Error check_size_t(size_t value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "size_t %s=" SIZE_FORMAT " is outside the allowed range " "[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -231,29 +232,29 @@ public: } }; -class CommandLineFlagRange_double : public CommandLineFlagRange { +class JVMFlagRange_double : public JVMFlagRange { double _min; double _max; const double* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_double(const char* name, const double* ptr, double min, double max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_double(const char* name, const double* ptr, double min, double max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_double(*_ptr, verbose); } - Flag::Error check_double(double value, bool verbose = true) { + JVMFlag::Error check_double(double value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "double %s=%f is outside the allowed range " "[ %f ... %f ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -277,27 +278,27 @@ void emit_range_uint64_t(const char* /*name*/, const uint64_t* /*value*/) { / void emit_range_size_t(const char* /*name*/, const size_t* /*value*/) { /* NOP */ } void emit_range_double(const char* /*name*/, const double* /*value*/) { /* NOP */ } -// CommandLineFlagRange emitting code functions if range arguments are provided +// JVMFlagRange emitting code functions if range arguments are provided void emit_range_int(const char* name, const int* ptr, int min, int max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_int(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_int(name, ptr, min, max)); } void emit_range_intx(const char* name, const intx* ptr, intx min, intx max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_intx(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_intx(name, ptr, min, max)); } void emit_range_uint(const char* name, const uint* ptr, uint min, uint max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_uint(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_uint(name, ptr, min, max)); } void emit_range_uintx(const char* name, const uintx* ptr, uintx min, uintx max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_uintx(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_uintx(name, ptr, min, max)); } void emit_range_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_uint64_t(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_uint64_t(name, ptr, min, max)); } void emit_range_size_t(const char* name, const size_t* ptr, size_t min, size_t max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_size_t(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_size_t(name, ptr, min, max)); } void emit_range_double(const char* name, const double* ptr, double min, double max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_double(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_double(name, ptr, min, max)); } // Generate code to call emit_range_xxx function @@ -328,12 +329,12 @@ void emit_range_double(const char* name, const double* ptr, double min, double m #define EMIT_RANGE_CHECK(a, b) , a, b #define INITIAL_RANGES_SIZE 379 -GrowableArray* CommandLineFlagRangeList::_ranges = NULL; +GrowableArray* JVMFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them -void CommandLineFlagRangeList::init(void) { +void JVMFlagRangeList::init(void) { - _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_RANGES_SIZE, true); + _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_RANGES_SIZE, true); emit_range_no(NULL VM_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, EMIT_RANGE_PD_DEVELOPER_FLAG, @@ -403,10 +404,10 @@ void CommandLineFlagRangeList::init(void) { #endif // COMPILER2 } -CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) { - CommandLineFlagRange* found = NULL; +JVMFlagRange* JVMFlagRangeList::find(const char* name) { + JVMFlagRange* found = NULL; for (int i=0; iname(), name) == 0) { found = range; break; @@ -415,12 +416,12 @@ CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) { return found; } -void CommandLineFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); +void JVMFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { + JVMFlagRange* range = JVMFlagRangeList::find(name); if (range != NULL) { range->print(st); } else { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + JVMFlagConstraint* constraint = JVMFlagConstraintList::find(name); if (constraint != NULL) { assert(default_range_str_func!=NULL, "default_range_str_func must be provided"); st->print("%s", default_range_str_func()); @@ -430,12 +431,12 @@ void CommandLineFlagRangeList::print(outputStream* st, const char* name, RangeSt } } -bool CommandLineFlagRangeList::check_ranges() { +bool JVMFlagRangeList::check_ranges() { // Check ranges. bool status = true; for (int i=0; icheck(true) != Flag::SUCCESS) status = false; + JVMFlagRange* range = at(i); + if (range->check(true) != JVMFlag::SUCCESS) status = false; } return status; } diff --git a/src/hotspot/share/runtime/commandLineFlagRangeList.hpp b/src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp similarity index 56% rename from src/hotspot/share/runtime/commandLineFlagRangeList.hpp rename to src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp index 318973505a5..6fa23cea244 100644 --- a/src/hotspot/share/runtime/commandLineFlagRangeList.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp @@ -22,11 +22,11 @@ * */ -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP +#ifndef SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP +#define SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP #include "memory/metaspaceShared.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "utilities/growableArray.hpp" /* @@ -44,36 +44,36 @@ public: static void print(bool verbose, const char* msg, ...); }; -class CommandLineFlagRange : public CHeapObj { +class JVMFlagRange : public CHeapObj { private: const char* _name; public: // the "name" argument must be a string literal - CommandLineFlagRange(const char* name) { _name=name; } - ~CommandLineFlagRange() {} + JVMFlagRange(const char* name) { _name=name; } + ~JVMFlagRange() {} const char* name() { return _name; } - virtual Flag::Error check(bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual JVMFlag::Error check(bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } virtual void print(outputStream* st) { ; } }; -class CommandLineFlagRangeList : public AllStatic { - static GrowableArray* _ranges; +class JVMFlagRangeList : public AllStatic { + static GrowableArray* _ranges; public: static void init(); static int length() { return (_ranges != NULL) ? _ranges->length() : 0; } - static CommandLineFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } - static CommandLineFlagRange* find(const char* name); - static void add(CommandLineFlagRange* range) { _ranges->append(range); } + static JVMFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } + static JVMFlagRange* find(const char* name); + static void add(JVMFlagRange* range) { _ranges->append(range); } static void print(outputStream* st, const char* name, RangeStrFunc default_range_str_func); // Check the final values of all flags for ranges. static bool check_ranges(); }; -#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP +#endif // SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP diff --git a/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp similarity index 76% rename from src/hotspot/share/runtime/commandLineFlagWriteableList.cpp rename to src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp index 214e614afc8..a80d21c0d34 100644 --- a/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/plab.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" #include "runtime/os.hpp" #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -36,18 +36,18 @@ #include "jvmci/jvmci_globals.hpp" #endif -bool CommandLineFlagWriteable::is_writeable(void) { +bool JVMFlagWriteable::is_writeable(void) { return _writeable; } -void CommandLineFlagWriteable::mark_once(void) { +void JVMFlagWriteable::mark_once(void) { if (_type == Once) { _writeable = false; } } -void CommandLineFlagWriteable::mark_startup(void) { - if (_type == CommandLineFlagWriteable::CommandLineOnly) { +void JVMFlagWriteable::mark_startup(void) { + if (_type == JVMFlagWriteable::CommandLineOnly) { _writeable = false; } } @@ -67,30 +67,30 @@ void emit_writeable_uint64_t(const char* /*name*/) { /* NOP */ } void emit_writeable_size_t(const char* /*name*/) { /* NOP */ } void emit_writeable_double(const char* /*name*/) { /* NOP */ } -// CommandLineFlagWriteable emitting code functions if range arguments are provided -void emit_writeable_bool(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +// JVMFlagWriteable emitting code functions if range arguments are provided +void emit_writeable_bool(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_int(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_int(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_intx(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_intx(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_uint(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_uint(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_uintx(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_uintx(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_uint64_t(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_uint64_t(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_size_t(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_size_t(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_double(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_double(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } // Generate code to call emit_writeable_xxx function @@ -108,14 +108,14 @@ void emit_writeable_double(const char* name, CommandLineFlagWriteable::Writeable #define EMIT_WRITEABLE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_writeable_##type(#name // Generate type argument to pass into emit_writeable_xxx functions -#define EMIT_WRITEABLE(a) , CommandLineFlagWriteable::a +#define EMIT_WRITEABLE(a) , JVMFlagWriteable::a #define INITIAL_WRITEABLES_SIZE 2 -GrowableArray* CommandLineFlagWriteableList::_controls = NULL; +GrowableArray* JVMFlagWriteableList::_controls = NULL; -void CommandLineFlagWriteableList::init(void) { +void JVMFlagWriteableList::init(void) { - _controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_WRITEABLES_SIZE, true); + _controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_WRITEABLES_SIZE, true); emit_writeable_no(NULL VM_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG, EMIT_WRITEABLE_PD_DEVELOPER_FLAG, @@ -185,10 +185,10 @@ void CommandLineFlagWriteableList::init(void) { #endif // COMPILER2 } -CommandLineFlagWriteable* CommandLineFlagWriteableList::find(const char* name) { - CommandLineFlagWriteable* found = NULL; +JVMFlagWriteable* JVMFlagWriteableList::find(const char* name) { + JVMFlagWriteable* found = NULL; for (int i=0; iname(), name) == 0) { found = writeable; break; @@ -197,9 +197,9 @@ CommandLineFlagWriteable* CommandLineFlagWriteableList::find(const char* name) { return found; } -void CommandLineFlagWriteableList::mark_startup(void) { +void JVMFlagWriteableList::mark_startup(void) { for (int i=0; imark_startup(); } } diff --git a/src/hotspot/share/runtime/commandLineFlagWriteableList.hpp b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp similarity index 70% rename from src/hotspot/share/runtime/commandLineFlagWriteableList.hpp rename to src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp index 84220851fb2..aca87e30f1f 100644 --- a/src/hotspot/share/runtime/commandLineFlagWriteableList.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp @@ -22,13 +22,12 @@ * */ -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP +#ifndef SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP +#define SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP -#include "runtime/globals.hpp" #include "utilities/growableArray.hpp" -class CommandLineFlagWriteable : public CHeapObj { +class JVMFlagWriteable : public CHeapObj { public: enum WriteableType { // can be set without any limits @@ -45,8 +44,8 @@ private: bool _startup_done; public: // the "name" argument must be a string literal - CommandLineFlagWriteable(const char* name, WriteableType type) { _name=name; _type=type; _writeable=true; _startup_done=false; } - ~CommandLineFlagWriteable() {} + JVMFlagWriteable(const char* name, WriteableType type) { _name=name; _type=type; _writeable=true; _startup_done=false; } + ~JVMFlagWriteable() {} const char* name() { return _name; } const WriteableType type() { return _type; } bool is_writeable(void); @@ -54,15 +53,15 @@ public: void mark_startup(void); }; -class CommandLineFlagWriteableList : public AllStatic { - static GrowableArray* _controls; +class JVMFlagWriteableList : public AllStatic { + static GrowableArray* _controls; public: static void init(); static int length() { return (_controls != NULL) ? _controls->length() : 0; } - static CommandLineFlagWriteable* at(int i) { return (_controls != NULL) ? _controls->at(i) : NULL; } - static CommandLineFlagWriteable* find(const char* name); - static void add(CommandLineFlagWriteable* range) { _controls->append(range); } + static JVMFlagWriteable* at(int i) { return (_controls != NULL) ? _controls->at(i) : NULL; } + static JVMFlagWriteable* find(const char* name); + static void add(JVMFlagWriteable* range) { _controls->append(range); } static void mark_startup(void); }; -#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP +#endif // SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP diff --git a/src/hotspot/share/runtime/globals.cpp b/src/hotspot/share/runtime/globals.cpp index 16054f408b1..3ee7d90df44 100644 --- a/src/hotspot/share/runtime/globals.cpp +++ b/src/hotspot/share/runtime/globals.cpp @@ -29,9 +29,9 @@ #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "trace/tracing.hpp" @@ -85,1473 +85,3 @@ ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ IGNORE_WRITEABLE) MATERIALIZE_FLAGS_EXT - -#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 -static char* create_range_str(const char *fmt, ...) { - static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; - static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); - - int size_needed = 0; - do { - va_list args; - va_start(args, fmt); - size_needed = jio_vsnprintf(range_string, string_length, fmt, args); - va_end(args); - - if (size_needed < 0) { - string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; - range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); - guarantee(range_string != NULL, "create_range_str string should not be NULL"); - } - } while (size_needed < 0); - - return range_string; -} - -const char* Flag::get_int_default_range_str() { - return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); -} - -const char* Flag::get_uint_default_range_str() { - return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); -} - -const char* Flag::get_intx_default_range_str() { - return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); -} - -const char* Flag::get_uintx_default_range_str() { - return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); -} - -const char* Flag::get_uint64_t_default_range_str() { - return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); -} - -const char* Flag::get_size_t_default_range_str() { - return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); -} - -const char* Flag::get_double_default_range_str() { - return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); -} - -static bool is_product_build() { -#ifdef PRODUCT - return true; -#else - return false; -#endif -} - -Flag::Error Flag::check_writable(bool changed) { - if (is_constant_in_binary()) { - fatal("flag is constant: %s", _name); - } - - Flag::Error error = Flag::SUCCESS; - if (changed) { - CommandLineFlagWriteable* writeable = CommandLineFlagWriteableList::find(_name); - if (writeable) { - if (writeable->is_writeable() == false) { - switch (writeable->type()) - { - case CommandLineFlagWriteable::Once: - error = Flag::SET_ONLY_ONCE; - jio_fprintf(defaultStream::error_stream(), "Error: %s may not be set more than once\n", _name); - break; - case CommandLineFlagWriteable::CommandLineOnly: - error = Flag::COMMAND_LINE_ONLY; - jio_fprintf(defaultStream::error_stream(), "Error: %s may be modified only from commad line\n", _name); - break; - default: - ShouldNotReachHere(); - break; - } - } - writeable->mark_once(); - } - } - return error; -} - -bool Flag::is_bool() const { - return strcmp(_type, "bool") == 0; -} - -bool Flag::get_bool() const { - return *((bool*) _addr); -} - -Flag::Error Flag::set_bool(bool value) { - Flag::Error error = check_writable(value!=get_bool()); - if (error == Flag::SUCCESS) { - *((bool*) _addr) = value; - } - return error; -} - -bool Flag::is_int() const { - return strcmp(_type, "int") == 0; -} - -int Flag::get_int() const { - return *((int*) _addr); -} - -Flag::Error Flag::set_int(int value) { - Flag::Error error = check_writable(value!=get_int()); - if (error == Flag::SUCCESS) { - *((int*) _addr) = value; - } - return error; -} - -bool Flag::is_uint() const { - return strcmp(_type, "uint") == 0; -} - -uint Flag::get_uint() const { - return *((uint*) _addr); -} - -Flag::Error Flag::set_uint(uint value) { - Flag::Error error = check_writable(value!=get_uint()); - if (error == Flag::SUCCESS) { - *((uint*) _addr) = value; - } - return error; -} - -bool Flag::is_intx() const { - return strcmp(_type, "intx") == 0; -} - -intx Flag::get_intx() const { - return *((intx*) _addr); -} - -Flag::Error Flag::set_intx(intx value) { - Flag::Error error = check_writable(value!=get_intx()); - if (error == Flag::SUCCESS) { - *((intx*) _addr) = value; - } - return error; -} - -bool Flag::is_uintx() const { - return strcmp(_type, "uintx") == 0; -} - -uintx Flag::get_uintx() const { - return *((uintx*) _addr); -} - -Flag::Error Flag::set_uintx(uintx value) { - Flag::Error error = check_writable(value!=get_uintx()); - if (error == Flag::SUCCESS) { - *((uintx*) _addr) = value; - } - return error; -} - -bool Flag::is_uint64_t() const { - return strcmp(_type, "uint64_t") == 0; -} - -uint64_t Flag::get_uint64_t() const { - return *((uint64_t*) _addr); -} - -Flag::Error Flag::set_uint64_t(uint64_t value) { - Flag::Error error = check_writable(value!=get_uint64_t()); - if (error == Flag::SUCCESS) { - *((uint64_t*) _addr) = value; - } - return error; -} - -bool Flag::is_size_t() const { - return strcmp(_type, "size_t") == 0; -} - -size_t Flag::get_size_t() const { - return *((size_t*) _addr); -} - -Flag::Error Flag::set_size_t(size_t value) { - Flag::Error error = check_writable(value!=get_size_t()); - if (error == Flag::SUCCESS) { - *((size_t*) _addr) = value; - } - return error; -} - -bool Flag::is_double() const { - return strcmp(_type, "double") == 0; -} - -double Flag::get_double() const { - return *((double*) _addr); -} - -Flag::Error Flag::set_double(double value) { - Flag::Error error = check_writable(value!=get_double()); - if (error == Flag::SUCCESS) { - *((double*) _addr) = value; - } - return error; -} - -bool Flag::is_ccstr() const { - return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; -} - -bool Flag::ccstr_accumulates() const { - return strcmp(_type, "ccstrlist") == 0; -} - -ccstr Flag::get_ccstr() const { - return *((ccstr*) _addr); -} - -Flag::Error Flag::set_ccstr(ccstr value) { - Flag::Error error = check_writable(value!=get_ccstr()); - if (error == Flag::SUCCESS) { - *((ccstr*) _addr) = value; - } - return error; -} - - -Flag::Flags Flag::get_origin() { - return Flags(_flags & VALUE_ORIGIN_MASK); -} - -void Flag::set_origin(Flags origin) { - assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); - Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); - _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); -} - -bool Flag::is_default() { - return (get_origin() == DEFAULT); -} - -bool Flag::is_ergonomic() { - return (get_origin() == ERGONOMIC); -} - -bool Flag::is_command_line() { - return (_flags & ORIG_COMMAND_LINE) != 0; -} - -void Flag::set_command_line() { - _flags = Flags(_flags | ORIG_COMMAND_LINE); -} - -bool Flag::is_product() const { - return (_flags & KIND_PRODUCT) != 0; -} - -bool Flag::is_manageable() const { - return (_flags & KIND_MANAGEABLE) != 0; -} - -bool Flag::is_diagnostic() const { - return (_flags & KIND_DIAGNOSTIC) != 0; -} - -bool Flag::is_experimental() const { - return (_flags & KIND_EXPERIMENTAL) != 0; -} - -bool Flag::is_notproduct() const { - return (_flags & KIND_NOT_PRODUCT) != 0; -} - -bool Flag::is_develop() const { - return (_flags & KIND_DEVELOP) != 0; -} - -bool Flag::is_read_write() const { - return (_flags & KIND_READ_WRITE) != 0; -} - -bool Flag::is_commercial() const { - return (_flags & KIND_COMMERCIAL) != 0; -} - -/** - * Returns if this flag is a constant in the binary. Right now this is - * true for notproduct and develop flags in product builds. - */ -bool Flag::is_constant_in_binary() const { -#ifdef PRODUCT - return is_notproduct() || is_develop(); -#else - return false; -#endif -} - -bool Flag::is_unlocker() const { - return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || - strcmp(_name, "UnlockExperimentalVMOptions") == 0 || - is_unlocker_ext(); -} - -bool Flag::is_unlocked() const { - if (is_diagnostic()) { - return UnlockDiagnosticVMOptions; - } - if (is_experimental()) { - return UnlockExperimentalVMOptions; - } - return is_unlocked_ext(); -} - -void Flag::clear_diagnostic() { - assert(is_diagnostic(), "sanity"); - _flags = Flags(_flags & ~KIND_DIAGNOSTIC); - assert(!is_diagnostic(), "sanity"); -} - -// Get custom message for this locked flag, or NULL if -// none is available. Returns message type produced. -Flag::MsgType Flag::get_locked_message(char* buf, int buflen) const { - buf[0] = '\0'; - if (is_diagnostic() && !is_unlocked()) { - jio_snprintf(buf, buflen, - "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" - "Error: The unlock option must precede '%s'.\n", - _name, _name); - return Flag::DIAGNOSTIC_FLAG_BUT_LOCKED; - } - if (is_experimental() && !is_unlocked()) { - jio_snprintf(buf, buflen, - "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" - "Error: The unlock option must precede '%s'.\n", - _name, _name); - return Flag::EXPERIMENTAL_FLAG_BUT_LOCKED; - } - if (is_develop() && is_product_build()) { - jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", - _name); - return Flag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; - } - if (is_notproduct() && is_product_build()) { - jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", - _name); - return Flag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; - } - return get_locked_message_ext(buf, buflen); -} - -bool Flag::is_writeable() const { - return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); -} - -// All flags except "manageable" are assumed to be internal flags. -// Long term, we need to define a mechanism to specify which flags -// are external/stable and change this function accordingly. -bool Flag::is_external() const { - return is_manageable() || is_external_ext(); -} - -// Helper function for Flag::print_on(). -// Fills current line up to requested position. -// Should the current position already be past the requested position, -// one separator blank is enforced. -void fill_to_pos(outputStream* st, unsigned int req_pos) { - if ((unsigned int)st->position() < req_pos) { - st->fill_to(req_pos); // need to fill with blanks to reach req_pos - } else { - st->print(" "); // enforce blank separation. Previous field too long. - } -} - -void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { - // Don't print notproduct and develop flags in a product build. - if (is_constant_in_binary()) { - return; - } - - if (!printRanges) { - // The command line options -XX:+PrintFlags* cause this function to be called - // for each existing flag to print information pertinent to this flag. The data - // is displayed in columnar form, with the following layout: - // col1 - data type, right-justified - // col2 - name, left-justified - // col3 - ' =' double-char, leading space to align with possible '+=' - // col4 - value left-justified - // col5 - kind right-justified - // col6 - origin left-justified - // col7 - comments left-justified - // - // The column widths are fixed. They are defined such that, for most cases, - // an eye-pleasing tabular output is created. - // - // Sample output: - // bool CMSScavengeBeforeRemark = false {product} {default} - // uintx CMSScheduleRemarkEdenPenetration = 50 {product} {default} - // size_t CMSScheduleRemarkEdenSizeThreshold = 2097152 {product} {default} - // uintx CMSScheduleRemarkSamplingRatio = 5 {product} {default} - // double CMSSmallCoalSurplusPercent = 1.050000 {product} {default} - // ccstr CompileCommandFile = MyFile.cmd {product} {command line} - // ccstrlist CompileOnly = Method1 - // CompileOnly += Method2 {product} {command line} - // | | | | | | | - // | | | | | | +-- col7 - // | | | | | +-- col6 - // | | | | +-- col5 - // | | | +-- col4 - // | | +-- col3 - // | +-- col2 - // +-- col1 - - const unsigned int col_spacing = 1; - const unsigned int col1_pos = 0; - const unsigned int col1_width = 9; - const unsigned int col2_pos = col1_pos + col1_width + col_spacing; - const unsigned int col2_width = 39; - const unsigned int col3_pos = col2_pos + col2_width + col_spacing; - const unsigned int col3_width = 2; - const unsigned int col4_pos = col3_pos + col3_width + col_spacing; - const unsigned int col4_width = 30; - const unsigned int col5_pos = col4_pos + col4_width + col_spacing; - const unsigned int col5_width = 20; - const unsigned int col6_pos = col5_pos + col5_width + col_spacing; - const unsigned int col6_width = 15; - const unsigned int col7_pos = col6_pos + col6_width + col_spacing; - const unsigned int col7_width = 1; - - st->fill_to(col1_pos); - st->print("%*s", col1_width, _type); // right-justified, therefore width is required. - - fill_to_pos(st, col2_pos); - st->print("%s", _name); - - fill_to_pos(st, col3_pos); - st->print(" ="); // use " =" for proper alignment with multiline ccstr output. - - fill_to_pos(st, col4_pos); - if (is_bool()) { - st->print("%s", get_bool() ? "true" : "false"); - } else if (is_int()) { - st->print("%d", get_int()); - } else if (is_uint()) { - st->print("%u", get_uint()); - } else if (is_intx()) { - st->print(INTX_FORMAT, get_intx()); - } else if (is_uintx()) { - st->print(UINTX_FORMAT, get_uintx()); - } else if (is_uint64_t()) { - st->print(UINT64_FORMAT, get_uint64_t()); - } else if (is_size_t()) { - st->print(SIZE_FORMAT, get_size_t()); - } else if (is_double()) { - st->print("%f", get_double()); - } else if (is_ccstr()) { - // Honor characters in ccstr: print multiple lines. - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - size_t llen = pointer_delta(eol, cp, sizeof(char)); - st->print("%.*s", (int)llen, cp); - st->cr(); - cp = eol+1; - fill_to_pos(st, col2_pos); - st->print("%s", _name); - fill_to_pos(st, col3_pos); - st->print("+="); - fill_to_pos(st, col4_pos); - } - st->print("%s", cp); - } - } else { - st->print("unhandled type %s", _type); - st->cr(); - return; - } - - fill_to_pos(st, col5_pos); - print_kind(st, col5_width); - - fill_to_pos(st, col6_pos); - print_origin(st, col6_width); - -#ifndef PRODUCT - if (withComments) { - fill_to_pos(st, col7_pos); - st->print("%s", _doc); - } -#endif - st->cr(); - } else if (!is_bool() && !is_ccstr()) { - // The command line options -XX:+PrintFlags* cause this function to be called - // for each existing flag to print information pertinent to this flag. The data - // is displayed in columnar form, with the following layout: - // col1 - data type, right-justified - // col2 - name, left-justified - // col4 - range [ min ... max] - // col5 - kind right-justified - // col6 - origin left-justified - // col7 - comments left-justified - // - // The column widths are fixed. They are defined such that, for most cases, - // an eye-pleasing tabular output is created. - // - // Sample output: - // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} - // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} - // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} - // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} - // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} - // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} - // | | | | | | - // | | | | | +-- col7 - // | | | | +-- col6 - // | | | +-- col5 - // | | +-- col4 - // | +-- col2 - // +-- col1 - - const unsigned int col_spacing = 1; - const unsigned int col1_pos = 0; - const unsigned int col1_width = 9; - const unsigned int col2_pos = col1_pos + col1_width + col_spacing; - const unsigned int col2_width = 49; - const unsigned int col3_pos = col2_pos + col2_width + col_spacing; - const unsigned int col3_width = 0; - const unsigned int col4_pos = col3_pos + col3_width + col_spacing; - const unsigned int col4_width = 60; - const unsigned int col5_pos = col4_pos + col4_width + col_spacing; - const unsigned int col5_width = 35; - const unsigned int col6_pos = col5_pos + col5_width + col_spacing; - const unsigned int col6_width = 15; - const unsigned int col7_pos = col6_pos + col6_width + col_spacing; - const unsigned int col7_width = 1; - - st->fill_to(col1_pos); - st->print("%*s", col1_width, _type); // right-justified, therefore width is required. - - fill_to_pos(st, col2_pos); - st->print("%s", _name); - - fill_to_pos(st, col4_pos); - RangeStrFunc func = NULL; - if (is_int()) { - func = Flag::get_int_default_range_str; - } else if (is_uint()) { - func = Flag::get_uint_default_range_str; - } else if (is_intx()) { - func = Flag::get_intx_default_range_str; - } else if (is_uintx()) { - func = Flag::get_uintx_default_range_str; - } else if (is_uint64_t()) { - func = Flag::get_uint64_t_default_range_str; - } else if (is_size_t()) { - func = Flag::get_size_t_default_range_str; - } else if (is_double()) { - func = Flag::get_double_default_range_str; - } else { - st->print("unhandled type %s", _type); - st->cr(); - return; - } - CommandLineFlagRangeList::print(st, _name, func); - - fill_to_pos(st, col5_pos); - print_kind(st, col5_width); - - fill_to_pos(st, col6_pos); - print_origin(st, col6_width); - -#ifndef PRODUCT - if (withComments) { - fill_to_pos(st, col7_pos); - st->print("%s", _doc); - } -#endif - st->cr(); - } -} - -void Flag::print_kind(outputStream* st, unsigned int width) { - struct Data { - int flag; - const char* name; - }; - - Data data[] = { - { KIND_JVMCI, "JVMCI" }, - { KIND_C1, "C1" }, - { KIND_C2, "C2" }, - { KIND_ARCH, "ARCH" }, - { KIND_PLATFORM_DEPENDENT, "pd" }, - { KIND_PRODUCT, "product" }, - { KIND_MANAGEABLE, "manageable" }, - { KIND_DIAGNOSTIC, "diagnostic" }, - { KIND_EXPERIMENTAL, "experimental" }, - { KIND_COMMERCIAL, "commercial" }, - { KIND_NOT_PRODUCT, "notproduct" }, - { KIND_DEVELOP, "develop" }, - { KIND_LP64_PRODUCT, "lp64_product" }, - { KIND_READ_WRITE, "rw" }, - { -1, "" } - }; - - if ((_flags & KIND_MASK) != 0) { - bool is_first = true; - const size_t buffer_size = 64; - size_t buffer_used = 0; - char kind[buffer_size]; - - jio_snprintf(kind, buffer_size, "{"); - buffer_used++; - for (int i = 0; data[i].flag != -1; i++) { - Data d = data[i]; - if ((_flags & d.flag) != 0) { - if (is_first) { - is_first = false; - } else { - assert(buffer_used + 1 < buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); - buffer_used++; - } - size_t length = strlen(d.name); - assert(buffer_used + length < buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); - buffer_used += length; - } - } - assert(buffer_used + 2 <= buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); - st->print("%*s", width, kind); - } -} - -void Flag::print_origin(outputStream* st, unsigned int width) { - int origin = _flags & VALUE_ORIGIN_MASK; - st->print("{"); - switch(origin) { - case DEFAULT: - st->print("default"); break; - case COMMAND_LINE: - st->print("command line"); break; - case ENVIRON_VAR: - st->print("environment"); break; - case CONFIG_FILE: - st->print("config file"); break; - case MANAGEMENT: - st->print("management"); break; - case ERGONOMIC: - if (_flags & ORIG_COMMAND_LINE) { - st->print("command line, "); - } - st->print("ergonomic"); break; - case ATTACH_ON_DEMAND: - st->print("attach"); break; - case INTERNAL: - st->print("internal"); break; - } - st->print("}"); -} - -void Flag::print_as_flag(outputStream* st) { - if (is_bool()) { - st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); - } else if (is_int()) { - st->print("-XX:%s=%d", _name, get_int()); - } else if (is_uint()) { - st->print("-XX:%s=%u", _name, get_uint()); - } else if (is_intx()) { - st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); - } else if (is_uintx()) { - st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); - } else if (is_uint64_t()) { - st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); - } else if (is_size_t()) { - st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); - } else if (is_double()) { - st->print("-XX:%s=%f", _name, get_double()); - } else if (is_ccstr()) { - st->print("-XX:%s=", _name); - const char* cp = get_ccstr(); - if (cp != NULL) { - // Need to turn embedded '\n's back into separate arguments - // Not so efficient to print one character at a time, - // but the choice is to do the transformation to a buffer - // and print that. And this need not be efficient. - for (; *cp != '\0'; cp += 1) { - switch (*cp) { - default: - st->print("%c", *cp); - break; - case '\n': - st->print(" -XX:%s=", _name); - break; - } - } - } - } else { - ShouldNotReachHere(); - } -} - -const char* Flag::flag_error_str(Flag::Error error) { - switch (error) { - case Flag::MISSING_NAME: return "MISSING_NAME"; - case Flag::MISSING_VALUE: return "MISSING_VALUE"; - case Flag::NON_WRITABLE: return "NON_WRITABLE"; - case Flag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; - case Flag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; - case Flag::INVALID_FLAG: return "INVALID_FLAG"; - case Flag::ERR_OTHER: return "ERR_OTHER"; - case Flag::SUCCESS: return "SUCCESS"; - default: ShouldNotReachHere(); return "NULL"; - } -} - -// 4991491 do not "optimize out" the was_set false values: omitting them -// tickles a Microsoft compiler bug causing flagTable to be malformed - -#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT) }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC) }, -#define RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_EXPERIMENTAL) }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_MANAGEABLE) }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_READ_WRITE) }, -#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP) }, -#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, - -#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT) }, -#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC) }, -#define JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_EXPERIMENTAL) }, -#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP) }, -#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_NOT_PRODUCT) }, - -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, -#else -#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ -#endif // _LP64 - -#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT) }, -#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC) }, -#define C1_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP) }, -#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_NOT_PRODUCT) }, - -#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT) }, -#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC) }, -#define C2_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_EXPERIMENTAL) }, -#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP) }, -#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_NOT_PRODUCT) }, - -#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_PRODUCT) }, -#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DIAGNOSTIC) }, -#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_EXPERIMENTAL) }, -#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DEVELOP) }, -#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) }, - -static Flag flagTable[] = { - VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PRODUCT_FLAG_STRUCT, \ - RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ - RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \ - RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ - RUNTIME_MANAGEABLE_FLAG_STRUCT, \ - RUNTIME_PRODUCT_RW_FLAG_STRUCT, \ - RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) - - RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PRODUCT_FLAG_STRUCT, \ - RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ - RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#if INCLUDE_JVMCI - JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ - JVMCI_PD_DEVELOP_FLAG_STRUCT, \ - JVMCI_PRODUCT_FLAG_STRUCT, \ - JVMCI_PD_PRODUCT_FLAG_STRUCT, \ - JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ - JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT, \ - JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ - JVMCI_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // INCLUDE_JVMCI -#ifdef COMPILER1 - C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ - C1_PD_DEVELOP_FLAG_STRUCT, \ - C1_PRODUCT_FLAG_STRUCT, \ - C1_PD_PRODUCT_FLAG_STRUCT, \ - C1_DIAGNOSTIC_FLAG_STRUCT, \ - C1_PD_DIAGNOSTIC_FLAG_STRUCT, \ - C1_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // COMPILER1 -#ifdef COMPILER2 - C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \ - C2_PD_DEVELOP_FLAG_STRUCT, \ - C2_PRODUCT_FLAG_STRUCT, \ - C2_PD_PRODUCT_FLAG_STRUCT, \ - C2_DIAGNOSTIC_FLAG_STRUCT, \ - C2_PD_DIAGNOSTIC_FLAG_STRUCT, \ - C2_EXPERIMENTAL_FLAG_STRUCT, \ - C2_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // COMPILER2 - ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ - ARCH_PRODUCT_FLAG_STRUCT, \ - ARCH_DIAGNOSTIC_FLAG_STRUCT, \ - ARCH_EXPERIMENTAL_FLAG_STRUCT, \ - ARCH_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) - FLAGTABLE_EXT - {0, NULL, NULL} -}; - -Flag* Flag::flags = flagTable; -size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag)); - -inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { - if (s_len != q_len) return false; - return memcmp(s, q, q_len) == 0; -} - -// Search the flag table for a named flag -Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { - for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { - if (str_equal(current->_name, current->get_name_length(), name, length)) { - // Found a matching entry. - // Don't report notproduct and develop flags in product builds. - if (current->is_constant_in_binary()) { - return (return_flag ? current : NULL); - } - // Report locked flags only if allowed. - if (!(current->is_unlocked() || current->is_unlocker())) { - if (!allow_locked) { - // disable use of locked flags, e.g. diagnostic, experimental, - // commercial... until they are explicitly unlocked - return NULL; - } - } - return current; - } - } - // Flag name is not in the flag table - return NULL; -} - -// Get or compute the flag name length -size_t Flag::get_name_length() { - if (_name_len == 0) { - _name_len = strlen(_name); - } - return _name_len; -} - -Flag* Flag::fuzzy_match(const char* name, size_t length, bool allow_locked) { - float VMOptionsFuzzyMatchSimilarity = 0.7f; - Flag* match = NULL; - float score; - float max_score = -1; - - for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { - score = StringUtils::similarity(current->_name, strlen(current->_name), name, length); - if (score > max_score) { - max_score = score; - match = current; - } - } - - if (!(match->is_unlocked() || match->is_unlocker())) { - if (!allow_locked) { - return NULL; - } - } - - if (max_score < VMOptionsFuzzyMatchSimilarity) { - return NULL; - } - - return match; -} - -// Returns the address of the index'th element -static Flag* address_of_flag(CommandLineFlagWithType flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - return &Flag::flags[flag]; -} - -bool CommandLineFlagsEx::is_default(CommandLineFlag flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - Flag* f = &Flag::flags[flag]; - return f->is_default(); -} - -bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - Flag* f = &Flag::flags[flag]; - return f->is_ergonomic(); -} - -bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - Flag* f = &Flag::flags[flag]; - return f->is_command_line(); -} - -bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) { - Flag* result = Flag::find_flag((char*)name, strlen(name)); - if (result == NULL) return false; - *value = result->is_command_line(); - return true; -} - -void CommandLineFlagsEx::setOnCmdLine(CommandLineFlagWithType flag) { - Flag* faddr = address_of_flag(flag); - assert(faddr != NULL, "Unknown flag"); - faddr->set_command_line(); -} - -template -static void trace_flag_changed(const char* name, const T old_value, const T new_value, const Flag::Flags origin) { - E e; - e.set_name(name); - e.set_oldValue(old_value); - e.set_newValue(new_value); - e.set_origin(origin); - e.commit(); -} - -static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_bool(new_value, verbose); - } - return status; -} - -Flag::Error CommandLineFlags::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_bool()) return Flag::WRONG_FORMAT; - *value = result->get_bool(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::boolAtPut(Flag* flag, bool* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_bool()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_bool(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - bool old_value = flag->get_bool(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_bool(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return boolAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); - return CommandLineFlags::boolAtPut(faddr, &value, origin); -} - -static Flag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_int(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_int(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_int()) return Flag::WRONG_FORMAT; - *value = result->get_int(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::intAtPut(Flag* flag, int* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_int()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_int(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - int old_value = flag->get_int(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_int(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return intAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_int(), "wrong flag type"); - return CommandLineFlags::intAtPut(faddr, &value, origin); -} - -static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uint(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uint(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_uint()) return Flag::WRONG_FORMAT; - *value = result->get_uint(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::uintAtPut(Flag* flag, uint* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_uint()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_uint(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - uint old_value = flag->get_uint(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return uintAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type"); - return CommandLineFlags::uintAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_intx()) return Flag::WRONG_FORMAT; - *value = result->get_intx(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_intx(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_intx(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::intxAtPut(Flag* flag, intx* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_intx()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_intx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - intx old_value = flag->get_intx(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_intx(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return intxAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); - return CommandLineFlags::intxAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_uintx()) return Flag::WRONG_FORMAT; - *value = result->get_uintx(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uintx(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uintx(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_uintx()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_uintx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - uintx old_value = flag->get_uintx(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uintx(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return uintxAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); - return CommandLineFlags::uintxAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_uint64_t()) return Flag::WRONG_FORMAT; - *value = result->get_uint64_t(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uint64_t(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uint64_t(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_uint64_t()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - uint64_t old_value = flag->get_uint64_t(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint64_t(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return uint64_tAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); - return CommandLineFlags::uint64_tAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_size_t()) return Flag::WRONG_FORMAT; - *value = result->get_size_t(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_size_t(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_size_t(new_value, verbose); - } - } - return status; -} - - -Flag::Error CommandLineFlags::size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_size_t()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_size_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - size_t old_value = flag->get_size_t(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_size_t(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return size_tAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); - return CommandLineFlags::size_tAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_double()) return Flag::WRONG_FORMAT; - *value = result->get_double(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_double(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_double(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::doubleAtPut(Flag* flag, double* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_double()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_double(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - double old_value = flag->get_double(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_double(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return doubleAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); - return CommandLineFlags::doubleAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_ccstr()) return Flag::WRONG_FORMAT; - *value = result->get_ccstr(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_ccstr()) return Flag::WRONG_FORMAT; - ccstr old_value = result->get_ccstr(); - trace_flag_changed(name, old_value, *value, origin); - char* new_value = NULL; - if (*value != NULL) { - new_value = os::strdup_check_oom(*value); - } - Flag::Error check = result->set_ccstr(new_value); - if (result->is_default() && old_value != NULL) { - // Prior value is NOT heap allocated, but was a literal constant. - old_value = os::strdup_check_oom(old_value); - } - *value = old_value; - result->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); - ccstr old_value = faddr->get_ccstr(); - trace_flag_changed(faddr->_name, old_value, value, origin); - char* new_value = os::strdup_check_oom(value); - Flag::Error check = faddr->set_ccstr(new_value); - if (!faddr->is_default() && old_value != NULL) { - // Prior value is heap allocated so free it. - FREE_C_HEAP_ARRAY(char, old_value); - } - faddr->set_origin(origin); - return check; -} - -extern "C" { - static int compare_flags(const void* void_a, const void* void_b) { - return strcmp((*((Flag**) void_a))->_name, (*((Flag**) void_b))->_name); - } -} - -void CommandLineFlags::printSetFlags(outputStream* out) { - // Print which flags were set on the command line - // note: this method is called before the thread structure is in place - // which means resource allocation cannot be used. - - // The last entry is the null entry. - const size_t length = Flag::numFlags - 1; - - // Sort - Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments); - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(Flag*), compare_flags); - - // Print - for (size_t i = 0; i < length; i++) { - if (array[i]->get_origin() /* naked field! */) { - array[i]->print_as_flag(out); - out->print(" "); - } - } - out->cr(); - FREE_C_HEAP_ARRAY(Flag*, array); -} - -#ifndef PRODUCT - -void CommandLineFlags::verify() { - assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); -} - -#endif // PRODUCT - -void CommandLineFlags::printFlags(outputStream* out, bool withComments, bool printRanges) { - // Print the flags sorted by name - // note: this method is called before the thread structure is in place - // which means resource allocation cannot be used. - - // The last entry is the null entry. - const size_t length = Flag::numFlags - 1; - - // Sort - Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments); - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(Flag*), compare_flags); - - // Print - if (!printRanges) { - out->print_cr("[Global flags]"); - } else { - out->print_cr("[Global flags ranges]"); - } - - for (size_t i = 0; i < length; i++) { - if (array[i]->is_unlocked()) { - array[i]->print_on(out, withComments, printRanges); - } - } - FREE_C_HEAP_ARRAY(Flag*, array); -} diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index bdd3c420bc3..0344c99a2d8 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -108,349 +108,6 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); #endif // no compilers -// string type aliases used only in this file -typedef const char* ccstr; -typedef const char* ccstrlist; // represents string arguments which accumulate - -// function type that will construct default range string -typedef const char* (*RangeStrFunc)(void); - -struct Flag { - enum Flags { - // latest value origin - DEFAULT = 0, - COMMAND_LINE = 1, - ENVIRON_VAR = 2, - CONFIG_FILE = 3, - MANAGEMENT = 4, - ERGONOMIC = 5, - ATTACH_ON_DEMAND = 6, - INTERNAL = 7, - - LAST_VALUE_ORIGIN = INTERNAL, - VALUE_ORIGIN_BITS = 4, - VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), - - // flag kind - KIND_PRODUCT = 1 << 4, - KIND_MANAGEABLE = 1 << 5, - KIND_DIAGNOSTIC = 1 << 6, - KIND_EXPERIMENTAL = 1 << 7, - KIND_NOT_PRODUCT = 1 << 8, - KIND_DEVELOP = 1 << 9, - KIND_PLATFORM_DEPENDENT = 1 << 10, - KIND_READ_WRITE = 1 << 11, - KIND_C1 = 1 << 12, - KIND_C2 = 1 << 13, - KIND_ARCH = 1 << 14, - KIND_LP64_PRODUCT = 1 << 15, - KIND_COMMERCIAL = 1 << 16, - KIND_JVMCI = 1 << 17, - - // set this bit if the flag was set on the command line - ORIG_COMMAND_LINE = 1 << 18, - - KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) - }; - - enum Error { - // no error - SUCCESS = 0, - // flag name is missing - MISSING_NAME, - // flag value is missing - MISSING_VALUE, - // error parsing the textual form of the value - WRONG_FORMAT, - // flag is not writable - NON_WRITABLE, - // flag value is outside of its bounds - OUT_OF_BOUNDS, - // flag value violates its constraint - VIOLATES_CONSTRAINT, - // there is no flag with the given name - INVALID_FLAG, - // the flag can only be set only on command line during invocation of the VM - COMMAND_LINE_ONLY, - // the flag may only be set once - SET_ONLY_ONCE, - // the flag is not writable in this combination of product/debug build - CONSTANT, - // other, unspecified error related to setting the flag - ERR_OTHER - }; - - enum MsgType { - NONE = 0, - DIAGNOSTIC_FLAG_BUT_LOCKED, - EXPERIMENTAL_FLAG_BUT_LOCKED, - DEVELOPER_FLAG_BUT_PRODUCT_BUILD, - NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD, - COMMERCIAL_FLAG_BUT_DISABLED, - COMMERCIAL_FLAG_BUT_LOCKED - }; - - const char* _type; - const char* _name; - void* _addr; - NOT_PRODUCT(const char* _doc;) - Flags _flags; - size_t _name_len; - - // points to all Flags static array - static Flag* flags; - - // number of flags - static size_t numFlags; - - static Flag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); }; - static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); - static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); - - static const char* get_int_default_range_str(); - static const char* get_uint_default_range_str(); - static const char* get_intx_default_range_str(); - static const char* get_uintx_default_range_str(); - static const char* get_uint64_t_default_range_str(); - static const char* get_size_t_default_range_str(); - static const char* get_double_default_range_str(); - - Flag::Error check_writable(bool changed); - - bool is_bool() const; - bool get_bool() const; - Flag::Error set_bool(bool value); - - bool is_int() const; - int get_int() const; - Flag::Error set_int(int value); - - bool is_uint() const; - uint get_uint() const; - Flag::Error set_uint(uint value); - - bool is_intx() const; - intx get_intx() const; - Flag::Error set_intx(intx value); - - bool is_uintx() const; - uintx get_uintx() const; - Flag::Error set_uintx(uintx value); - - bool is_uint64_t() const; - uint64_t get_uint64_t() const; - Flag::Error set_uint64_t(uint64_t value); - - bool is_size_t() const; - size_t get_size_t() const; - Flag::Error set_size_t(size_t value); - - bool is_double() const; - double get_double() const; - Flag::Error set_double(double value); - - bool is_ccstr() const; - bool ccstr_accumulates() const; - ccstr get_ccstr() const; - Flag::Error set_ccstr(ccstr value); - - Flags get_origin(); - void set_origin(Flags origin); - - size_t get_name_length(); - - bool is_default(); - bool is_ergonomic(); - bool is_command_line(); - void set_command_line(); - - bool is_product() const; - bool is_manageable() const; - bool is_diagnostic() const; - bool is_experimental() const; - bool is_notproduct() const; - bool is_develop() const; - bool is_read_write() const; - bool is_commercial() const; - - bool is_constant_in_binary() const; - - bool is_unlocker() const; - bool is_unlocked() const; - bool is_writeable() const; - bool is_external() const; - - bool is_unlocker_ext() const; - bool is_unlocked_ext() const; - bool is_writeable_ext() const; - bool is_external_ext() const; - - void clear_diagnostic(); - - Flag::MsgType get_locked_message(char*, int) const; - Flag::MsgType get_locked_message_ext(char*, int) const; - - // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges - void print_on(outputStream* st, bool withComments = false, bool printRanges = false); - void print_kind(outputStream* st, unsigned int width); - void print_origin(outputStream* st, unsigned int width); - void print_as_flag(outputStream* st); - - static const char* flag_error_str(Flag::Error error); -}; - -// debug flags control various aspects of the VM and are global accessible - -// use FlagSetting to temporarily change some debug flag -// e.g. FlagSetting fs(DebugThisAndThat, true); -// restored to previous value upon leaving scope -class FlagSetting { - bool val; - bool* flag; - public: - FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; } - ~FlagSetting() { *flag = val; } -}; - - -class CounterSetting { - intx* counter; - public: - CounterSetting(intx* cnt) { counter = cnt; (*counter)++; } - ~CounterSetting() { (*counter)--; } -}; - -class IntFlagSetting { - int val; - int* flag; - public: - IntFlagSetting(int& fl, int newValue) { flag = &fl; val = fl; fl = newValue; } - ~IntFlagSetting() { *flag = val; } -}; - -class UIntFlagSetting { - uint val; - uint* flag; - public: - UIntFlagSetting(uint& fl, uint newValue) { flag = &fl; val = fl; fl = newValue; } - ~UIntFlagSetting() { *flag = val; } -}; - -class UIntXFlagSetting { - uintx val; - uintx* flag; - public: - UIntXFlagSetting(uintx& fl, uintx newValue) { flag = &fl; val = fl; fl = newValue; } - ~UIntXFlagSetting() { *flag = val; } -}; - -class DoubleFlagSetting { - double val; - double* flag; - public: - DoubleFlagSetting(double& fl, double newValue) { flag = &fl; val = fl; fl = newValue; } - ~DoubleFlagSetting() { *flag = val; } -}; - -class SizeTFlagSetting { - size_t val; - size_t* flag; - public: - SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } - ~SizeTFlagSetting() { *flag = val; } -}; - -// Helper class for temporarily saving the value of a flag during a scope. -template -class FlagGuard { - unsigned char _value[SIZE]; - void* const _addr; - - // Hide operator new, this class should only be allocated on the stack. - // NOTE: Cannot include memory/allocation.hpp here due to circular - // dependencies. - void* operator new(size_t size) throw(); - void* operator new [](size_t size) throw(); - - public: - FlagGuard(void* flag_addr) : _addr(flag_addr) { - memcpy(_value, _addr, SIZE); - } - - ~FlagGuard() { - memcpy(_addr, _value, SIZE); - } -}; - -#define FLAG_GUARD(f) FlagGuard f ## _guard(&f) - -class CommandLineFlags { -public: - static Flag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error boolAtPut(Flag* flag, bool* value, Flag::Flags origin); - static Flag::Error boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin); - static Flag::Error boolAtPut(const char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } - - static Flag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error intAtPut(Flag* flag, int* value, Flag::Flags origin); - static Flag::Error intAtPut(const char* name, size_t len, int* value, Flag::Flags origin); - static Flag::Error intAtPut(const char* name, int* value, Flag::Flags origin) { return intAtPut(name, strlen(name), value, origin); } - - static Flag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error uintAtPut(Flag* flag, uint* value, Flag::Flags origin); - static Flag::Error uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin); - static Flag::Error uintAtPut(const char* name, uint* value, Flag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); } - - static Flag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error intxAtPut(Flag* flag, intx* value, Flag::Flags origin); - static Flag::Error intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin); - static Flag::Error intxAtPut(const char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } - - static Flag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin); - static Flag::Error uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin); - static Flag::Error uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } - - static Flag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin); - static Flag::Error size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin); - static Flag::Error size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } - - static Flag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin); - static Flag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin); - static Flag::Error uint64_tAtPut(const char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } - - static Flag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error doubleAtPut(Flag* flag, double* value, Flag::Flags origin); - static Flag::Error doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin); - static Flag::Error doubleAtPut(const char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } - - static Flag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); } - // Contract: Flag will make private copy of the incoming value. - // Outgoing value is always malloc-ed, and caller MUST call free. - static Flag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin); - static Flag::Error ccstrAtPut(const char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } - - // Returns false if name is not a command line flag. - static bool wasSetOnCmdline(const char* name, bool* value); - static void printSetFlags(outputStream* out); - - // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges - static void printFlags(outputStream* out, bool withComments, bool printRanges = false); - - static void verify() PRODUCT_RETURN; -}; - // use this for flags that are true by default in the debug version but // false in the optimized version, and vice versa #ifdef ASSERT @@ -536,10 +193,10 @@ public: // it can be done in the same way as product_rw. // // range is a macro that will expand to min and max arguments for range -// checking code if provided - see commandLineFlagRangeList.hpp +// checking code if provided - see jvmFlagRangeList.hpp // // constraint is a macro that will expand to custom function call -// for constraint checking if provided - see commandLineFlagConstraintList.hpp +// for constraint checking if provided - see jvmFlagConstraintList.hpp // // writeable is a macro that controls if and how the value can change during the runtime // diff --git a/src/hotspot/share/runtime/globals_ext.hpp b/src/hotspot/share/runtime/globals_ext.hpp index f3d4c992668..b1802493b61 100644 --- a/src/hotspot/share/runtime/globals_ext.hpp +++ b/src/hotspot/share/runtime/globals_ext.hpp @@ -27,11 +27,11 @@ // globals_extension.hpp extension -// Additional CommandLineFlags enum values -#define COMMANDLINEFLAG_EXT +// Additional JVMFlags enum values +#define JVMFLAGS_EXT -// Additional CommandLineFlagsWithType enum values -#define COMMANDLINEFLAGWITHTYPE_EXT +// Additional JVMFlagsWithType enum values +#define JVMFLAGSWITHTYPE_EXT // globals.cpp extension @@ -45,26 +45,26 @@ // Default method implementations -inline bool Flag::is_unlocker_ext() const { +inline bool JVMFlag::is_unlocker_ext() const { return false; } -inline bool Flag::is_unlocked_ext() const { +inline bool JVMFlag::is_unlocked_ext() const { return true; } -inline bool Flag::is_writeable_ext() const { +inline bool JVMFlag::is_writeable_ext() const { return false; } -inline bool Flag::is_external_ext() const { +inline bool JVMFlag::is_external_ext() const { return false; } -inline Flag::MsgType Flag::get_locked_message_ext(char* buf, int buflen) const { +inline JVMFlag::MsgType JVMFlag::get_locked_message_ext(char* buf, int buflen) const { assert(buf != NULL, "Buffer cannot be NULL"); buf[0] = '\0'; - return Flag::NONE; + return JVMFlag::NONE; } #endif // SHARE_VM_RUNTIME_GLOBALS_EXT_HPP diff --git a/src/hotspot/share/runtime/globals_extension.hpp b/src/hotspot/share/runtime/globals_extension.hpp index 38c8701715f..0297b3d08db 100644 --- a/src/hotspot/share/runtime/globals_extension.hpp +++ b/src/hotspot/share/runtime/globals_extension.hpp @@ -27,7 +27,6 @@ #include "runtime/globals.hpp" #include "utilities/macros.hpp" -#include "utilities/macros.hpp" #if INCLUDE_JVMCI #include "jvmci/jvmci_globals.hpp" #endif @@ -164,9 +163,9 @@ typedef enum { IGNORE_RANGE, \ IGNORE_CONSTRAINT, \ IGNORE_WRITEABLE) - COMMANDLINEFLAG_EXT - NUM_CommandLineFlag -} CommandLineFlag; + JVMFLAGS_EXT + NUM_JVMFlags +} JVMFlags; // Construct enum of Flag__ constants. @@ -293,19 +292,19 @@ typedef enum { IGNORE_RANGE, IGNORE_CONSTRAINT, IGNORE_WRITEABLE) - COMMANDLINEFLAGWITHTYPE_EXT - NUM_CommandLineFlagWithType -} CommandLineFlagWithType; + JVMFLAGSWITHTYPE_EXT + NUM_JVMFlagsWithType +} JVMFlagsWithType; -#define FLAG_IS_DEFAULT(name) (CommandLineFlagsEx::is_default(FLAG_MEMBER(name))) -#define FLAG_IS_ERGO(name) (CommandLineFlagsEx::is_ergo(FLAG_MEMBER(name))) -#define FLAG_IS_CMDLINE(name) (CommandLineFlagsEx::is_cmdline(FLAG_MEMBER(name))) +#define FLAG_IS_DEFAULT(name) (JVMFlagEx::is_default(FLAG_MEMBER(name))) +#define FLAG_IS_ERGO(name) (JVMFlagEx::is_ergo(FLAG_MEMBER(name))) +#define FLAG_IS_CMDLINE(name) (JVMFlagEx::is_cmdline(FLAG_MEMBER(name))) #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) -#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \ - CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), Flag::COMMAND_LINE)) -#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), Flag::ERGONOMIC)) +#define FLAG_SET_CMDLINE(type, name, value) (JVMFlagEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \ + JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::COMMAND_LINE)) +#define FLAG_SET_ERGO(type, name, value) (JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::ERGONOMIC)) #define FLAG_SET_ERGO_IF_DEFAULT(type, name, value) \ do { \ if (FLAG_IS_DEFAULT(name)) { \ @@ -313,26 +312,26 @@ typedef enum { } \ } while (0) -// Can't put the following in CommandLineFlags because +// Can't put the following in JVMFlags because // of a circular dependency on the enum definition. -class CommandLineFlagsEx : CommandLineFlags { +class JVMFlagEx : JVMFlag { public: - static Flag::Error boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin); - static Flag::Error intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin); - static Flag::Error uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin); - static Flag::Error intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin); - static Flag::Error uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin); - static Flag::Error uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin); - static Flag::Error size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin); - static Flag::Error doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin); + static JVMFlag::Error boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin); + static JVMFlag::Error intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin); + static JVMFlag::Error uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin); + static JVMFlag::Error intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin); + static JVMFlag::Error uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin); + static JVMFlag::Error uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin); + static JVMFlag::Error size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin); + static JVMFlag::Error doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin); // Contract: Flag will make private copy of the incoming value - static Flag::Error ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin); + static JVMFlag::Error ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin); - static bool is_default(CommandLineFlag flag); - static bool is_ergo(CommandLineFlag flag); - static bool is_cmdline(CommandLineFlag flag); + static bool is_default(JVMFlags flag); + static bool is_ergo(JVMFlags flag); + static bool is_cmdline(JVMFlags flag); - static void setOnCmdLine(CommandLineFlagWithType flag); + static void setOnCmdLine(JVMFlagsWithType flag); }; #endif // SHARE_VM_RUNTIME_GLOBALS_EXTENSION_HPP diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index a903eef7c39..7836e558888 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_HANDSHAKE_HPP #include "memory/allocation.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/semaphore.hpp" class ThreadClosure; diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 944ddeb83a9..6c4d000267f 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -30,7 +30,7 @@ #include "interpreter/bytecodes.hpp" #include "memory/universe.hpp" #include "prims/methodHandles.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" #include "runtime/init.hpp" @@ -155,7 +155,7 @@ jint init_globals() { // All the flags that get adjusted by VM_Version_init and os::init_2 // have been set so dump the flags now. if (PrintFlagsFinal || PrintFlagsRanges) { - CommandLineFlags::printFlags(tty, false, PrintFlagsRanges); + JVMFlag::printFlags(tty, false, PrintFlagsRanges); } return JNI_OK; diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index c1c8a3d1bca..fd17e47a48e 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -54,6 +54,7 @@ #include "runtime/biasedLocking.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 7a0cd44c099..e94dcd0286e 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_MUTEXLOCKER_HPP #include "memory/allocation.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/mutex.hpp" // Mutexes used in the VM. diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index b70e3025039..ff9a38a3d45 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -63,12 +63,11 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" -#include "runtime/globals.hpp" #include "runtime/handshake.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -3663,17 +3662,17 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { if (ergo_result != JNI_OK) return ergo_result; // Final check of all ranges after ergonomics which may change values. - if (!CommandLineFlagRangeList::check_ranges()) { + if (!JVMFlagRangeList::check_ranges()) { return JNI_EINVAL; } // Final check of all 'AfterErgo' constraints after ergonomics which may change values. - bool constraint_result = CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterErgo); + bool constraint_result = JVMFlagConstraintList::check_constraints(JVMFlagConstraint::AfterErgo); if (!constraint_result) { return JNI_EINVAL; } - CommandLineFlagWriteableList::mark_startup(); + JVMFlagWriteableList::mark_startup(); if (PauseAtStartup) { os::pause(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 8ad9b2a6e5d..ccce40e837e 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -82,6 +82,7 @@ #include "prims/jvmtiAgentThread.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" @@ -717,7 +718,7 @@ typedef PaddedEnd PaddedObjectMonitor; nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ - nonstatic_field(nmethod, _state, volatile signed char) \ + nonstatic_field(nmethod, _state, volatile signed char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ @@ -1059,12 +1060,12 @@ typedef PaddedEnd PaddedObjectMonitor; /* -XX flags */ \ /*********************/ \ \ - nonstatic_field(Flag, _type, const char*) \ - nonstatic_field(Flag, _name, const char*) \ - unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) /* NOTE: no type */ \ - nonstatic_field(Flag, _flags, Flag::Flags) \ - static_field(Flag, flags, Flag*) \ - static_field(Flag, numFlags, size_t) \ + nonstatic_field(JVMFlag, _type, const char*) \ + nonstatic_field(JVMFlag, _name, const char*) \ + unchecked_nonstatic_field(JVMFlag, _addr, sizeof(void*)) /* NOTE: no type */ \ + nonstatic_field(JVMFlag, _flags, JVMFlag::Flags) \ + static_field(JVMFlag, flags, JVMFlag*) \ + static_field(JVMFlag, numFlags, size_t) \ \ /*************************/ \ /* JDK / VM version info */ \ @@ -1431,18 +1432,18 @@ typedef PaddedEnd PaddedObjectMonitor; declare_toplevel_type(SharedRuntime) \ \ declare_toplevel_type(CodeBlob) \ - declare_type(RuntimeBlob, CodeBlob) \ - declare_type(BufferBlob, RuntimeBlob) \ + declare_type(RuntimeBlob, CodeBlob) \ + declare_type(BufferBlob, RuntimeBlob) \ declare_type(AdapterBlob, BufferBlob) \ declare_type(MethodHandlesAdapterBlob, BufferBlob) \ declare_type(CompiledMethod, CodeBlob) \ declare_type(nmethod, CompiledMethod) \ - declare_type(RuntimeStub, RuntimeBlob) \ - declare_type(SingletonBlob, RuntimeBlob) \ + declare_type(RuntimeStub, RuntimeBlob) \ + declare_type(SingletonBlob, RuntimeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ - declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ + declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -1896,8 +1897,8 @@ typedef PaddedEnd PaddedObjectMonitor; /* -XX flags */ \ /********************/ \ \ - declare_toplevel_type(Flag) \ - declare_toplevel_type(Flag*) \ + declare_toplevel_type(JVMFlag) \ + declare_toplevel_type(JVMFlag*) \ \ /********************/ \ /* JVMTI */ \ @@ -1937,7 +1938,7 @@ typedef PaddedEnd PaddedObjectMonitor; declare_integer_type(ThreadState) \ declare_integer_type(Location::Type) \ declare_integer_type(Location::Where) \ - declare_integer_type(Flag::Flags) \ + declare_integer_type(JVMFlag::Flags) \ COMPILER2_PRESENT(declare_integer_type(OptoReg::Name)) \ \ declare_toplevel_type(CHeapObj) \ diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index ff4705cb8f6..8264727e086 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -31,6 +31,7 @@ #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -275,9 +276,9 @@ static jint set_flag(AttachOperation* op, outputStream* out) { FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), Flag::ATTACH_ON_DEMAND, err_msg); - if (ret != Flag::SUCCESS) { - if (ret == Flag::NON_WRITABLE) { + int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); + if (ret != JVMFlag::SUCCESS) { + if (ret == JVMFlag::NON_WRITABLE) { // if the flag is not manageable try to change it through // the platform dependent implementation return AttachListener::pd_set_flag(op, out); @@ -298,7 +299,7 @@ static jint print_flag(AttachOperation* op, outputStream* out) { out->print_cr("flag name is missing"); return JNI_ERR; } - Flag* f = Flag::find_flag((char*)name, strlen(name)); + JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name)); if (f) { f->print_as_flag(out); out->cr(); diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index ce7de97dffa..0c5388168a8 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -33,7 +33,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" @@ -231,9 +231,9 @@ PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) : void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) { if (_all.value()) { - CommandLineFlags::printFlags(output(), true); + JVMFlag::printFlags(output(), true); } else { - CommandLineFlags::printSetFlags(output()); + JVMFlag::printSetFlags(output()); } } @@ -264,9 +264,9 @@ void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) { } FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(_flag.value(), val, Flag::MANAGEMENT, err_msg); + int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlag::MANAGEMENT, err_msg); - if (ret != Flag::SUCCESS) { + if (ret != JVMFlag::SUCCESS) { output()->print_cr("%s", err_msg.buffer()); } } diff --git a/src/hotspot/share/services/dtraceAttacher.cpp b/src/hotspot/share/services/dtraceAttacher.cpp index d923bc1282e..2d7e32c2ddc 100644 --- a/src/hotspot/share/services/dtraceAttacher.cpp +++ b/src/hotspot/share/services/dtraceAttacher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "code/codeCache.hpp" #include "memory/resourceArea.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/dtraceAttacher.hpp" @@ -50,8 +51,8 @@ class VM_DeoptimizeTheWorld : public VM_Operation { }; static void set_bool_flag(const char* flag, bool value) { - CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value, - Flag::ATTACH_ON_DEMAND); + JVMFlag::boolAtPut((char*)flag, strlen(flag), &value, + JVMFlag::ATTACH_ON_DEMAND); } // Enable only the "fine grained" flags. Do *not* touch diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index a75ae1a6a43..ec44089c18f 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -36,6 +36,7 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -866,10 +867,10 @@ static jint get_vm_thread_count() { static jint get_num_flags() { // last flag entry is always NULL, so subtract 1 - int nFlags = (int) Flag::numFlags - 1; + int nFlags = (int) JVMFlag::numFlags - 1; int count = 0; for (int i = 0; i < nFlags; i++) { - Flag* flag = &Flag::flags[i]; + JVMFlag* flag = &JVMFlag::flags[i]; // Exclude the locked (diagnostic, experimental) flags if (flag->is_unlocked() || flag->is_unlocker()) { count++; @@ -1419,14 +1420,14 @@ JVM_END // Returns a String array of all VM global flag names JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env)) // last flag entry is always NULL, so subtract 1 - int nFlags = (int) Flag::numFlags - 1; + int nFlags = (int) JVMFlag::numFlags - 1; // allocate a temp array objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), nFlags, CHECK_0); objArrayHandle flags_ah(THREAD, r); int num_entries = 0; for (int i = 0; i < nFlags; i++) { - Flag* flag = &Flag::flags[i]; + JVMFlag* flag = &JVMFlag::flags[i]; // Exclude notproduct and develop flags in product builds. if (flag->is_constant_in_binary()) { continue; @@ -1454,7 +1455,7 @@ JVM_END // Utility function used by jmm_GetVMGlobals. Returns false if flag type // can't be determined, true otherwise. If false is returned, then *global // will be incomplete and invalid. -bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { +bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, JVMFlag *flag, TRAPS) { Handle flag_name; if (name() == NULL) { flag_name = java_lang_String::create_from_str(flag->_name, CHECK_false); @@ -1499,25 +1500,25 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, global->writeable = flag->is_writeable(); global->external = flag->is_external(); switch (flag->get_origin()) { - case Flag::DEFAULT: + case JVMFlag::DEFAULT: global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT; break; - case Flag::COMMAND_LINE: + case JVMFlag::COMMAND_LINE: global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE; break; - case Flag::ENVIRON_VAR: + case JVMFlag::ENVIRON_VAR: global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR; break; - case Flag::CONFIG_FILE: + case JVMFlag::CONFIG_FILE: global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE; break; - case Flag::MANAGEMENT: + case JVMFlag::MANAGEMENT: global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT; break; - case Flag::ERGONOMIC: + case JVMFlag::ERGONOMIC: global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC; break; - case Flag::ATTACH_ON_DEMAND: + case JVMFlag::ATTACH_ON_DEMAND: global->origin = JMM_VMGLOBAL_ORIGIN_ATTACH_ON_DEMAND; break; default: @@ -1531,7 +1532,7 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, // specified by names. If names == NULL, fill globals array // with all Flags. Return value is number of entries // created in globals. -// If a Flag with a given name in an array element does not +// If a JVMFlag with a given name in an array element does not // exist, globals[i].name will be set to NULL. JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, jobjectArray names, @@ -1566,7 +1567,7 @@ JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, Handle sh(THREAD, s); char* str = java_lang_String::as_utf8_string(s); - Flag* flag = Flag::find_flag(str, strlen(str)); + JVMFlag* flag = JVMFlag::find_flag(str, strlen(str)); if (flag != NULL && add_global_entry(env, sh, &globals[i], flag, THREAD)) { num_entries++; @@ -1579,11 +1580,11 @@ JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, // return all globals if names == NULL // last flag entry is always NULL, so subtract 1 - int nFlags = (int) Flag::numFlags - 1; + int nFlags = (int) JVMFlag::numFlags - 1; Handle null_h; int num_entries = 0; for (int i = 0; i < nFlags && num_entries < count; i++) { - Flag* flag = &Flag::flags[i]; + JVMFlag* flag = &JVMFlag::flags[i]; // Exclude notproduct and develop flags in product builds. if (flag->is_constant_in_binary()) { continue; @@ -1609,10 +1610,10 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value char* name = java_lang_String::as_utf8_string(fn); FormatBuffer<80> error_msg("%s", ""); - int succeed = WriteableFlags::set_flag(name, new_value, Flag::MANAGEMENT, error_msg); + int succeed = WriteableFlags::set_flag(name, new_value, JVMFlag::MANAGEMENT, error_msg); - if (succeed != Flag::SUCCESS) { - if (succeed == Flag::MISSING_VALUE) { + if (succeed != JVMFlag::SUCCESS) { + if (succeed == JVMFlag::MISSING_VALUE) { // missing value causes NPE to be thrown THROW(vmSymbols::java_lang_NullPointerException()); } else { @@ -1621,7 +1622,7 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value error_msg.buffer()); } } - assert(succeed == Flag::SUCCESS, "Setting flag should succeed"); + assert(succeed == JVMFlag::SUCCESS, "Setting flag should succeed"); JVM_END class ThreadTimesClosure: public ThreadClosure { diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp index 54b59635c2e..fee4e68b51f 100644 --- a/src/hotspot/share/services/writeableFlags.cpp +++ b/src/hotspot/share/services/writeableFlags.cpp @@ -26,7 +26,8 @@ #include "classfile/javaClasses.hpp" #include "memory/allocation.inline.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" #include "services/writeableFlags.hpp" @@ -38,7 +39,7 @@ static void buffer_concat(char* buffer, const char* src) { } static void print_flag_error_message_bounds(const char* name, char* buffer) { - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + JVMFlagRange* range = JVMFlagRangeList::find(name); if (range != NULL) { buffer_concat(buffer, "must have value in range "); @@ -58,34 +59,34 @@ static void print_flag_error_message_bounds(const char* name, char* buffer) { } } -static void print_flag_error_message_if_needed(Flag::Error error, const char* name, FormatBuffer<80>& err_msg) { - if (error == Flag::SUCCESS) { +static void print_flag_error_message_if_needed(JVMFlag::Error error, const char* name, FormatBuffer<80>& err_msg) { + if (error == JVMFlag::SUCCESS) { return; } char buffer[TEMP_BUF_SIZE] = {'\0'}; - if ((error != Flag::MISSING_NAME) && (name != NULL)) { + if ((error != JVMFlag::MISSING_NAME) && (name != NULL)) { buffer_concat(buffer, name); buffer_concat(buffer, " error: "); } else { buffer_concat(buffer, "Error: "); } switch (error) { - case Flag::MISSING_NAME: + case JVMFlag::MISSING_NAME: buffer_concat(buffer, "flag name is missing."); break; - case Flag::MISSING_VALUE: + case JVMFlag::MISSING_VALUE: buffer_concat(buffer, "parsing the textual form of the value."); break; - case Flag::NON_WRITABLE: + case JVMFlag::NON_WRITABLE: buffer_concat(buffer, "flag is not writeable."); break; - case Flag::OUT_OF_BOUNDS: + case JVMFlag::OUT_OF_BOUNDS: print_flag_error_message_bounds(name, buffer); break; - case Flag::VIOLATES_CONSTRAINT: + case JVMFlag::VIOLATES_CONSTRAINT: buffer_concat(buffer, "value violates its flag's constraint."); break; - case Flag::INVALID_FLAG: + case JVMFlag::INVALID_FLAG: buffer_concat(buffer, "there is no flag with the given name."); break; - case Flag::ERR_OTHER: + case JVMFlag::ERR_OTHER: buffer_concat(buffer, "other, unspecified error related to setting the flag."); break; - case Flag::SUCCESS: + case JVMFlag::SUCCESS: break; default: break; @@ -95,127 +96,127 @@ static void print_flag_error_message_if_needed(Flag::Error error, const char* na } // set a boolean global flag -Flag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { if ((strcasecmp(arg, "true") == 0) || (*arg == '1' && *(arg + 1) == 0)) { return set_bool_flag(name, true, origin, err_msg); } else if ((strcasecmp(arg, "false") == 0) || (*arg == '0' && *(arg + 1) == 0)) { return set_bool_flag(name, false, origin, err_msg); } err_msg.print("flag value must be a boolean (1/0 or true/false)"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::boolAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::boolAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a int global flag -Flag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { int value; if (sscanf(arg, "%d", &value)) { return set_int_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::intAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::intAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uint global flag -Flag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { uint value; if (sscanf(arg, "%u", &value)) { return set_uint_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::uintAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::uintAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a intx global flag -Flag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { intx value; if (sscanf(arg, INTX_FORMAT, &value)) { return set_intx_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::intxAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::intxAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uintx global flag -Flag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { uintx value; if (sscanf(arg, UINTX_FORMAT, &value)) { return set_uintx_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::uintxAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::uintxAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uint64_t global flag -Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { uint64_t value; if (sscanf(arg, UINT64_FORMAT, &value)) { return set_uint64_t_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned 64-bit integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::uint64_tAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::uint64_tAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a size_t global flag -Flag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { size_t value; if (sscanf(arg, SIZE_FORMAT, &value)) { return set_size_t_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::size_tAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::size_tAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a string global flag using value from AttachOperation -Flag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::ccstrAtPut((char*)name, &value, origin); +JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::ccstrAtPut((char*)name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } @@ -225,7 +226,7 @@ Flag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -Flag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg); } @@ -234,42 +235,42 @@ Flag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_val * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -Flag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg); } // a writeable flag setter accepting either 'jvalue' or 'char *' values -Flag::Error WriteableFlags::set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*,const void*,Flag::Flags,FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlag::Flags,FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { if (name == NULL) { err_msg.print("flag name is missing"); - return Flag::MISSING_NAME; + return JVMFlag::MISSING_NAME; } if (value == NULL) { err_msg.print("flag value is missing"); - return Flag::MISSING_VALUE; + return JVMFlag::MISSING_VALUE; } - Flag* f = Flag::find_flag((char*)name, strlen(name)); + JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name)); if (f) { // only writeable flags are allowed to be set if (f->is_writeable()) { return setter(f, value, origin, err_msg); } else { err_msg.print("only 'writeable' flags can be set"); - return Flag::NON_WRITABLE; + return JVMFlag::NON_WRITABLE; } } err_msg.print("flag %s does not exist", name); - return Flag::INVALID_FLAG; + return JVMFlag::INVALID_FLAG; } // a writeable flag setter accepting 'char *' values -Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { char* flag_value = *(char**)value; if (flag_value == NULL) { err_msg.print("flag value is missing"); - return Flag::MISSING_VALUE; + return JVMFlag::MISSING_VALUE; } if (f->is_bool()) { return set_bool_flag(f->_name, flag_value, origin, err_msg); @@ -290,11 +291,11 @@ Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag: } else { ShouldNotReachHere(); } - return Flag::ERR_OTHER; + return JVMFlag::ERR_OTHER; } // a writeable flag setter accepting 'jvalue' values -Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, +JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { jvalue new_value = *(jvalue*)value; if (f->is_bool()) { @@ -322,16 +323,16 @@ Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Fla oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { err_msg.print("flag value is missing"); - return Flag::MISSING_VALUE; + return JVMFlag::MISSING_VALUE; } ccstr svalue = java_lang_String::as_utf8_string(str); - Flag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg); - if (ret != Flag::SUCCESS) { + JVMFlag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg); + if (ret != JVMFlag::SUCCESS) { FREE_C_HEAP_ARRAY(char, svalue); } return ret; } else { ShouldNotReachHere(); } - return Flag::ERR_OTHER; + return JVMFlag::ERR_OTHER; } diff --git a/src/hotspot/share/services/writeableFlags.hpp b/src/hotspot/share/services/writeableFlags.hpp index caa6e0a4757..31065982c4c 100644 --- a/src/hotspot/share/services/writeableFlags.hpp +++ b/src/hotspot/share/services/writeableFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,48 +25,49 @@ #ifndef SHARE_VM_SERVICES_WRITEABLEFLAG_HPP #define SHARE_VM_SERVICES_WRITEABLEFLAG_HPP +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "utilities/formatBuffer.hpp" class WriteableFlags : AllStatic { private: // a writeable flag setter accepting either 'jvalue' or 'char *' values - static Flag::Error set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*, const void*, Flag::Flags, FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*, const void*, JVMFlag::Flags, FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'char *' values - static Flag::Error set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'jvalue' values - static Flag::Error set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static Flag::Error set_bool_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_bool_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a int global flag - static Flag::Error set_int_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_int_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint global flag - static Flag::Error set_uint_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a intx global flag - static Flag::Error set_intx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_intx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static Flag::Error set_uintx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uintx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static Flag::Error set_uint64_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint64_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static Flag::Error set_size_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_size_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static Flag::Error set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a int global flag - static Flag::Error set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint global flag - static Flag::Error set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a intx global flag - static Flag::Error set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static Flag::Error set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static Flag::Error set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static Flag::Error set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a string global flag - static Flag::Error set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); public: /* sets a writeable flag to the provided value @@ -74,14 +75,14 @@ public: * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static Flag::Error set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); /* sets a writeable flag to the provided value * * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static Flag::Error set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); }; #endif /* SHARE_VM_SERVICES_WRITEABLEFLAG_HPP */ diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 71bbe5709e2..1fa5d655058 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -40,6 +40,7 @@ #include "prims/privilegedStack.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index a6b9fdef58c..91772d15eba 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1259,4 +1259,11 @@ static inline void* dereference_vptr(const void* addr) { return *(void**)addr; } +//---------------------------------------------------------------------------------------------------- +// String type aliases used by command line flag declarations and +// processing utilities. + +typedef const char* ccstr; +typedef const char* ccstrlist; // represents string arguments which accumulate + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_HPP diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index fe180f189e2..a89820857ac 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,7 +136,7 @@ public class VM { private Boolean compressedOopsEnabled; private Boolean compressedKlassPointersEnabled; - // command line flags supplied to VM - see struct Flag in globals.hpp + // command line flags supplied to VM - see struct JVMFlag in jvmFlag.hpp public static final class Flag { private String type; private String name; @@ -905,7 +905,7 @@ public class VM { private void readCommandLineFlags() { // get command line flags TypeDataBase db = getTypeDataBase(); - Type flagType = db.lookupType("Flag"); + Type flagType = db.lookupType("JVMFlag"); int numFlags = (int) flagType.getCIntegerField("numFlags").getValue(); // NOTE: last flag contains null values. commandLineFlags = new Flag[numFlags - 1]; diff --git a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp index 5fd493fa802..ce50b73a690 100644 --- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp +++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/collectorPolicy.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/test/hotspot/gtest/runtime/test_globals.cpp b/test/hotspot/gtest/runtime/test_globals.cpp index 3a84f2ce714..d2d3ed262af 100644 --- a/test/hotspot/gtest/runtime/test_globals.cpp +++ b/test/hotspot/gtest/runtime/test_globals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,18 @@ #include "precompiled.hpp" #include "runtime/globals.hpp" +#include "runtime/flags/flagSetting.hpp" #include "unittest.hpp" -#define TEST_FLAG(f, type, value) \ - do { \ - ASSERT_TRUE(Flag::find_flag(#f)->is_ ## type()); \ - type original_value = f; \ - { \ - FLAG_GUARD(f); \ - f = value; \ - } \ - ASSERT_EQ(original_value, f); \ +#define TEST_FLAG(f, type, value) \ + do { \ + ASSERT_TRUE(JVMFlag::find_flag(#f)->is_ ## type()); \ + type original_value = f; \ + { \ + FLAG_GUARD(f); \ + f = value; \ + } \ + ASSERT_EQ(original_value, f); \ } while (0) TEST_VM(FlagGuard, bool_flag) { From 54d482220b39d343a0fbd6a59f6b64163f05a211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 23 Apr 2018 18:14:35 +0200 Subject: [PATCH 017/102] 8198816: AbstractScriptEngine.getScriptContext creation of SimpleScriptContext is inefficient Reviewed-by: sundar, jlaskey --- .../javax/script/AbstractScriptEngine.java | 6 +----- .../classes/javax/script/CompiledScript.java | 5 +---- .../javax/script/SimpleScriptContext.java | 20 ++++++++++++++++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/java.scripting/share/classes/javax/script/AbstractScriptEngine.java b/src/java.scripting/share/classes/javax/script/AbstractScriptEngine.java index 7c9eb00ef10..f34de5cc8bc 100644 --- a/src/java.scripting/share/classes/javax/script/AbstractScriptEngine.java +++ b/src/java.scripting/share/classes/javax/script/AbstractScriptEngine.java @@ -287,7 +287,7 @@ public abstract class AbstractScriptEngine implements ScriptEngine { */ protected ScriptContext getScriptContext(Bindings nn) { - SimpleScriptContext ctxt = new SimpleScriptContext(); + SimpleScriptContext ctxt = new SimpleScriptContext(context.getReader(), context.getWriter(), context.getErrorWriter()); Bindings gs = getBindings(ScriptContext.GLOBAL_SCOPE); if (gs != null) { @@ -301,10 +301,6 @@ public abstract class AbstractScriptEngine implements ScriptEngine { throw new NullPointerException("Engine scope Bindings may not be null."); } - ctxt.setReader(context.getReader()); - ctxt.setWriter(context.getWriter()); - ctxt.setErrorWriter(context.getErrorWriter()); - return ctxt; } diff --git a/src/java.scripting/share/classes/javax/script/CompiledScript.java b/src/java.scripting/share/classes/javax/script/CompiledScript.java index 7fb4157d70a..5dc8738aaf1 100644 --- a/src/java.scripting/share/classes/javax/script/CompiledScript.java +++ b/src/java.scripting/share/classes/javax/script/CompiledScript.java @@ -79,13 +79,10 @@ public abstract class CompiledScript { ScriptContext ctxt = getEngine().getContext(); if (bindings != null) { - SimpleScriptContext tempctxt = new SimpleScriptContext(); + SimpleScriptContext tempctxt = new SimpleScriptContext(ctxt.getReader(), ctxt.getWriter(), ctxt.getErrorWriter()); tempctxt.setBindings(bindings, ScriptContext.ENGINE_SCOPE); tempctxt.setBindings(ctxt.getBindings(ScriptContext.GLOBAL_SCOPE), ScriptContext.GLOBAL_SCOPE); - tempctxt.setWriter(ctxt.getWriter()); - tempctxt.setReader(ctxt.getReader()); - tempctxt.setErrorWriter(ctxt.getErrorWriter()); ctxt = tempctxt; } diff --git a/src/java.scripting/share/classes/javax/script/SimpleScriptContext.java b/src/java.scripting/share/classes/javax/script/SimpleScriptContext.java index 119b3f26fb3..dde6ddc7566 100644 --- a/src/java.scripting/share/classes/javax/script/SimpleScriptContext.java +++ b/src/java.scripting/share/classes/javax/script/SimpleScriptContext.java @@ -86,11 +86,25 @@ public class SimpleScriptContext implements ScriptContext { * Create a {@code SimpleScriptContext}. */ public SimpleScriptContext() { + this(new InputStreamReader(System.in), + new PrintWriter(System.out , true), + new PrintWriter(System.err, true)); engineScope = new SimpleBindings(); globalScope = null; - reader = new InputStreamReader(System.in); - writer = new PrintWriter(System.out , true); - errorWriter = new PrintWriter(System.err, true); + } + + /** + * Package-private constructor to avoid needless creation of reader and writers. + * It is the caller's responsability to initialize the engine scope. + * + * @param reader the reader + * @param writer the writer + * @param errorWriter the error writer + */ + SimpleScriptContext(Reader reader, Writer writer, Writer errorWriter) { + this.reader = reader; + this.writer = writer; + this.errorWriter = errorWriter; } /** From d1f838a28518e741926ddc507697aadb8c849e01 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Mon, 23 Apr 2018 11:37:46 -0700 Subject: [PATCH 018/102] 8201259: Fix warning with VS2017 in jdk.pack Reviewed-by: erikj --- make/launcher/Launcher-jdk.pack.gmk | 1 - make/lib/Lib-jdk.pack.gmk | 1 - src/jdk.pack/share/native/common-unpack/utils.h | 10 +++++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/make/launcher/Launcher-jdk.pack.gmk b/make/launcher/Launcher-jdk.pack.gmk index c66bed0d4e5..1e7debfda32 100644 --- a/make/launcher/Launcher-jdk.pack.gmk +++ b/make/launcher/Launcher-jdk.pack.gmk @@ -88,7 +88,6 @@ $(eval $(call SetupJdkExecutable, BUILD_UNPACKEXE, \ CFLAGS_solaris := -KPIC, \ CFLAGS_macosx := -fPIC, \ DISABLED_WARNINGS_gcc := unused-result implicit-fallthrough, \ - DISABLED_WARNINGS_microsoft := 4005, \ LDFLAGS := $(UNPACKEXE_ZIPOBJS) \ $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ diff --git a/make/lib/Lib-jdk.pack.gmk b/make/lib/Lib-jdk.pack.gmk index 35fe7a41d4d..9884818852c 100644 --- a/make/lib/Lib-jdk.pack.gmk +++ b/make/lib/Lib-jdk.pack.gmk @@ -40,7 +40,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBUNPACK, \ $(LIBJAVA_HEADER_FLAGS), \ CFLAGS_release := -DPRODUCT, \ DISABLED_WARNINGS_gcc := implicit-fallthrough, \ - DISABLED_WARNINGS_microsoft := 4005, \ LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \ diff --git a/src/jdk.pack/share/native/common-unpack/utils.h b/src/jdk.pack/share/native/common-unpack/utils.h index 89619316a0e..5cd11edd7e9 100644 --- a/src/jdk.pack/share/native/common-unpack/utils.h +++ b/src/jdk.pack/share/native/common-unpack/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,16 +33,16 @@ void mtrace(char c, void* ptr, size_t size); #endif // overflow management -#define OVERFLOW ((uint)-1) -#define PSIZE_MAX (OVERFLOW/2) /* normal size limit */ +#define POVERFLOW ((uint)-1) +#define PSIZE_MAX (POVERFLOW/2) /* normal size limit */ inline size_t scale_size(size_t size, size_t scale) { - return (size > PSIZE_MAX / scale) ? OVERFLOW : size * scale; + return (size > PSIZE_MAX / scale) ? POVERFLOW : size * scale; } inline size_t add_size(size_t size1, size_t size2) { return ((size1 | size2 | (size1 + size2)) > PSIZE_MAX) - ? OVERFLOW + ? POVERFLOW : size1 + size2; } From 816e2e5fe00f4c7125f9bdf664c80af25d25e6d5 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 23 Apr 2018 14:51:16 -0500 Subject: [PATCH 019/102] 8202151: [BACKOUT] Split globals.hpp to factor out the Flag class Backed out JDK-8081519 Reviewed-by: kvn --- .../cpu/aarch64/methodHandles_aarch64.cpp | 1 - .../cpu/sparc/macroAssembler_sparc.cpp | 1 - src/hotspot/cpu/sparc/methodHandles_sparc.cpp | 1 - src/hotspot/cpu/x86/macroAssembler_x86.cpp | 1 - src/hotspot/cpu/x86/methodHandles_x86.cpp | 1 - src/hotspot/share/code/dependencies.cpp | 1 - src/hotspot/share/code/nmethod.cpp | 1 - src/hotspot/share/code/relocInfo.cpp | 3 +- ....cpp => commandLineFlagConstraintsCMS.cpp} | 88 +- ....hpp => commandLineFlagConstraintsCMS.hpp} | 26 +- .../gc/cms/concurrentMarkSweepGeneration.cpp | 1 - ...1.cpp => commandLineFlagConstraintsG1.cpp} | 64 +- ...1.hpp => commandLineFlagConstraintsG1.hpp} | 18 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 - ...=> commandLineFlagConstraintsParallel.cpp} | 20 +- ...=> commandLineFlagConstraintsParallel.hpp} | 6 +- src/hotspot/share/gc/parallel/psMarkSweep.cpp | 1 - ...C.cpp => commandLineFlagConstraintsGC.cpp} | 202 +-- .../shared/commandLineFlagConstraintsGC.hpp | 73 + .../share/gc/shared/genCollectedHeap.cpp | 1 - .../share/gc/shared/jvmFlagConstraintsGC.hpp | 73 - src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 3 +- .../share/jvmci/jvmciCompilerToVMInit.cpp | 5 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 23 +- src/hotspot/share/memory/universe.cpp | 5 +- src/hotspot/share/oops/klassVtable.cpp | 1 - src/hotspot/share/precompiled/precompiled.hpp | 11 - src/hotspot/share/prims/whitebox.cpp | 57 +- src/hotspot/share/runtime/arguments.cpp | 236 +-- src/hotspot/share/runtime/arguments.hpp | 7 +- ....cpp => commandLineFlagConstraintList.cpp} | 184 +- .../runtime/commandLineFlagConstraintList.hpp | 101 ++ ...=> commandLineFlagConstraintsCompiler.cpp} | 133 +- .../commandLineFlagConstraintsCompiler.hpp | 75 + ... => commandLineFlagConstraintsRuntime.cpp} | 57 +- ... => commandLineFlagConstraintsRuntime.hpp} | 25 +- ...eList.cpp => commandLineFlagRangeList.cpp} | 143 +- ...eList.hpp => commandLineFlagRangeList.hpp} | 40 +- ...t.cpp => commandLineFlagWriteableList.cpp} | 62 +- ...t.hpp => commandLineFlagWriteableList.hpp} | 23 +- .../share/runtime/flags/flagSetting.hpp | 71 - src/hotspot/share/runtime/flags/jvmFlag.cpp | 1506 ----------------- src/hotspot/share/runtime/flags/jvmFlag.hpp | 283 ---- .../runtime/flags/jvmFlagConstraintList.hpp | 101 -- .../flags/jvmFlagConstraintsCompiler.hpp | 74 - src/hotspot/share/runtime/globals.cpp | 1476 +++++++++++++++- src/hotspot/share/runtime/globals.hpp | 347 +++- src/hotspot/share/runtime/globals_ext.hpp | 20 +- .../share/runtime/globals_extension.hpp | 55 +- src/hotspot/share/runtime/handshake.hpp | 1 - src/hotspot/share/runtime/init.cpp | 4 +- src/hotspot/share/runtime/java.cpp | 1 - src/hotspot/share/runtime/mutexLocker.hpp | 1 - src/hotspot/share/runtime/thread.cpp | 13 +- src/hotspot/share/runtime/vmStructs.cpp | 31 +- src/hotspot/share/services/attachListener.cpp | 9 +- .../share/services/diagnosticCommand.cpp | 10 +- src/hotspot/share/services/dtraceAttacher.cpp | 7 +- src/hotspot/share/services/management.cpp | 41 +- src/hotspot/share/services/writeableFlags.cpp | 119 +- src/hotspot/share/services/writeableFlags.hpp | 43 +- src/hotspot/share/utilities/debug.cpp | 1 - .../share/utilities/globalDefinitions.hpp | 7 - .../classes/sun/jvm/hotspot/runtime/VM.java | 6 +- .../gtest/gc/shared/test_collectorPolicy.cpp | 3 +- test/hotspot/gtest/runtime/test_globals.cpp | 21 +- 66 files changed, 2966 insertions(+), 3060 deletions(-) rename src/hotspot/share/gc/cms/{jvmFlagConstraintsCMS.cpp => commandLineFlagConstraintsCMS.cpp} (78%) rename src/hotspot/share/gc/cms/{jvmFlagConstraintsCMS.hpp => commandLineFlagConstraintsCMS.hpp} (60%) rename src/hotspot/share/gc/g1/{jvmFlagConstraintsG1.cpp => commandLineFlagConstraintsG1.cpp} (76%) rename src/hotspot/share/gc/g1/{jvmFlagConstraintsG1.hpp => commandLineFlagConstraintsG1.hpp} (67%) rename src/hotspot/share/gc/parallel/{jvmFlagConstraintsParallel.cpp => commandLineFlagConstraintsParallel.cpp} (82%) rename src/hotspot/share/gc/parallel/{jvmFlagConstraintsParallel.hpp => commandLineFlagConstraintsParallel.hpp} (84%) rename src/hotspot/share/gc/shared/{jvmFlagConstraintsGC.cpp => commandLineFlagConstraintsGC.cpp} (71%) create mode 100644 src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp delete mode 100644 src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp rename src/hotspot/share/runtime/{flags/jvmFlagConstraintList.cpp => commandLineFlagConstraintList.cpp} (58%) create mode 100644 src/hotspot/share/runtime/commandLineFlagConstraintList.hpp rename src/hotspot/share/runtime/{flags/jvmFlagConstraintsCompiler.cpp => commandLineFlagConstraintsCompiler.cpp} (80%) create mode 100644 src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp rename src/hotspot/share/runtime/{flags/jvmFlagConstraintsRuntime.cpp => commandLineFlagConstraintsRuntime.cpp} (77%) rename src/hotspot/share/runtime/{flags/jvmFlagConstraintsRuntime.hpp => commandLineFlagConstraintsRuntime.hpp} (60%) rename src/hotspot/share/runtime/{flags/jvmFlagRangeList.cpp => commandLineFlagRangeList.cpp} (75%) rename src/hotspot/share/runtime/{flags/jvmFlagRangeList.hpp => commandLineFlagRangeList.hpp} (56%) rename src/hotspot/share/runtime/{flags/jvmFlagWriteableList.cpp => commandLineFlagWriteableList.cpp} (76%) rename src/hotspot/share/runtime/{flags/jvmFlagWriteableList.hpp => commandLineFlagWriteableList.hpp} (70%) delete mode 100644 src/hotspot/share/runtime/flags/flagSetting.hpp delete mode 100644 src/hotspot/share/runtime/flags/jvmFlag.cpp delete mode 100644 src/hotspot/share/runtime/flags/jvmFlag.hpp delete mode 100644 src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp delete mode 100644 src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index 8ae90a5f2c3..e717c1e7e96 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -30,7 +30,6 @@ #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" #include "prims/methodHandles.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #define __ _masm-> diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp index f2e1c901b02..b4a3052a998 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp @@ -35,7 +35,6 @@ #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/objectMonitor.hpp" diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp index f84ba5d0021..6076f7ab053 100644 --- a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp +++ b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp @@ -31,7 +31,6 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 15181a5d39e..43265c8acb2 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -37,7 +37,6 @@ #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index dc53107c735..e38515a6e7a 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -31,7 +31,6 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 1c97270a030..03c0ec89318 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -35,7 +35,6 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 65fefb0788d..c6e4f9e0ad5 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -47,7 +47,6 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "runtime/atomic.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 94fb1886b68..16e2ab8d849 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ #include "code/relocInfo.hpp" #include "memory/resourceArea.hpp" #include "oops/compressedOops.inline.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/copy.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp b/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp similarity index 78% rename from src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp rename to src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp index 777ed6ce13d..367f4e49e82 100644 --- a/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp +++ b/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp @@ -23,52 +23,52 @@ */ #include "precompiled.hpp" -#include "gc/cms/jvmFlagConstraintsCMS.hpp" +#include "gc/cms/commandLineFlagConstraintsCMS.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/jvmFlagConstraintsGC.hpp" +#include "gc/shared/commandLineFlagConstraintsGC.hpp" #include "memory/universe.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "utilities/globalDefinitions.hpp" -static JVMFlag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { +static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { // CMSWorkQueueDrainThreshold is verified to be less than max_juint if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { CommandLineError::print(verbose, "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" UINTX_FORMAT ") is too large\n", threads, threshold); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) { +Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) { // To avoid overflow at ParScanClosure::do_oop_work. if (UseConcMarkSweepGC && (value > (max_jint / 10))) { CommandLineError::print(verbose, "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for CMS GC\n", value, (max_jint / 10)); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose); } -JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) { CommandLineError::print(verbose, "ParGCStridesPerThread (" UINTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", value, ((uintx)max_jint / (uintx)ParallelGCThreads)); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { +Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { if (UseConcMarkSweepGC) { // ParGCCardsPerStrideChunk should be compared with card table size. size_t heap_size = Universe::heap()->reserved_region().word_size(); @@ -80,7 +80,7 @@ JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and " "must be less than or equal to card table size (" SIZE_FORMAT ")\n", value, card_table_size); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread) @@ -93,14 +93,14 @@ JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", value, ergo_max); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; +Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; if (UseConcMarkSweepGC) { if (value > CMSOldPLABMax) { @@ -108,15 +108,15 @@ JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { "CMSOldPLABMin (" SIZE_FORMAT ") must be " "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", value, CMSOldPLABMax); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); } return status; } -JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; if (UseConcMarkSweepGC) { status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); @@ -124,7 +124,7 @@ JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { return status; } -static JVMFlag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { +static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { if (UseConcMarkSweepGC) { ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen(); const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size(); @@ -134,17 +134,17 @@ static JVMFlag::Error CMSReservedAreaConstraintFunc(const char* name, size_t val "less than or equal to ergonomic maximum (" SIZE_FORMAT ") " "which is based on the maximum size of the old generation of the Java heap\n", name, value, ergo_max); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { - JVMFlag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); +Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { + Flag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); - if (status == JVMFlag::SUCCESS && UseConcMarkSweepGC) { + if (status == Flag::SUCCESS && UseConcMarkSweepGC) { // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size() // to be aligned to CardTable::card_size * BitsPerWord. // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize' @@ -154,40 +154,40 @@ JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { "CMSRescanMultiple (" SIZE_FORMAT ") must be " "a multiple of " SIZE_FORMAT "\n", value, HeapWordSize); - status = JVMFlag::VIOLATES_CONSTRAINT; + status = Flag::VIOLATES_CONSTRAINT; } } return status; } -JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { +Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose); } -JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { +Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { CommandLineError::print(verbose, "CMSPrecleanDenominator (" UINTX_FORMAT ") must be " "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n", value, CMSPrecleanNumerator); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { +Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) { CommandLineError::print(verbose, "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n", value, CMSPrecleanDenominator); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { +Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC) { size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity(); if (value > max_uintx - max_capacity) { @@ -195,20 +195,20 @@ JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { "CMSSamplingGrain (" UINTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n", value, max_uintx - max_capacity); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC) { return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose); } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { +Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { // Skip for current default value. if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) { // CMSBitMapYieldQuantum should be compared with mark bitmap size. @@ -221,18 +221,18 @@ JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { "be less than or equal to bitmap size (" SIZE_FORMAT ") " "whose size corresponds to the size of old generation of the Java heap\n", value, bitmap_size); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { +Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { if (value == 0) { CommandLineError::print(verbose, "OldPLABSize (" SIZE_FORMAT ") must be greater than 0", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } // For CMS, OldPLABSize is the number of free blocks of a given size that are used when // replenishing the local per-worker free list caches. diff --git a/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp b/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp similarity index 60% rename from src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp rename to src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp index eabb9fc3933..c147e92de99 100644 --- a/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp +++ b/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp @@ -29,20 +29,20 @@ #include "utilities/globalDefinitions.hpp" // CMS Flag Constraints -JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); -JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); -JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); -JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); -JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); -JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); -JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); -JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); -JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); -JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); -JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); +Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); +Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); +Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); +Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); +Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); +Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); +Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); // CMS Subconstraints -JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose); -JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose); +Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose); +Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose); #endif // SHARE_GC_CMS_COMMANDLINEFLAGCONSTRAINTSCMS_HPP diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp index 8efe5dde48b..a4d4c2facf6 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp @@ -68,7 +68,6 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/atomic.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp similarity index 76% rename from src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp rename to src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp index 43de961a1f6..eed1c456c01 100644 --- a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp @@ -24,12 +24,12 @@ #include "precompiled.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "utilities/globalDefinitions.hpp" -JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { - if (!UseG1GC) return JVMFlag::SUCCESS; +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; // Default value of G1RSetRegionEntries=0 means will be set ergonomically. // Minimum value is 1. @@ -38,14 +38,14 @@ JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { "G1RSetRegionEntries (" INTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { - if (!UseG1GC) return JVMFlag::SUCCESS; +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. // Minimum value is 1. @@ -54,14 +54,14 @@ JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { - if (!UseG1GC) return JVMFlag::SUCCESS; +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; // Default value of G1HeapRegionSize=0 means will be set ergonomically. if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { @@ -69,53 +69,53 @@ JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { "G1HeapRegionSize (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic heap region minimum size\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { - if (!UseG1GC) return JVMFlag::SUCCESS; +Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; if (value > G1MaxNewSizePercent) { CommandLineError::print(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n", value, G1MaxNewSizePercent); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { - if (!UseG1GC) return JVMFlag::SUCCESS; +Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; if (value < G1NewSizePercent) { CommandLineError::print(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n", value, G1NewSizePercent); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { +Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { CommandLineError::print(verbose, "MaxGCPauseMillis (" UINTX_FORMAT ") must be " "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n", value, GCPauseIntervalMillis); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { +Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC) { if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { if (value < 1) { @@ -123,14 +123,14 @@ JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { CommandLineError::print(verbose, "GCPauseIntervalMillis cannot be set " "without setting MaxGCPauseMillis\n"); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (value <= MaxGCPauseMillis) { @@ -138,15 +138,15 @@ JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n", value, MaxGCPauseMillis); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { +Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { #ifdef _LP64 // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length // when the value to be assigned exceeds uint range. @@ -156,10 +156,10 @@ JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { CommandLineError::print(verbose, "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif // _LP64 - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } size_t MaxSizeForHeapAlignmentG1() { diff --git a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp b/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp similarity index 67% rename from src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp rename to src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp index 29a98038296..a81bd4254e1 100644 --- a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp +++ b/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp @@ -29,17 +29,17 @@ #include "utilities/globalDefinitions.hpp" // G1 Flag Constraints -JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); -JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); -JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); -JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); +Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); +Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); // G1 Subconstraints -JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose); -JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose); -JVMFlag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose); -JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose); +Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose); +Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose); +Flag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose); +Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose); size_t MaxSizeForHeapAlignmentG1(); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 662d730018e..33cee250b01 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -84,7 +84,6 @@ #include "oops/oop.inline.hpp" #include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/orderAccess.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp b/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp similarity index 82% rename from src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp rename to src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp index ab95428b26e..54742369c1a 100644 --- a/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp +++ b/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp @@ -23,11 +23,11 @@ */ #include "precompiled.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" -JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { +Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. // So can't exceed with "max_jint" @@ -36,24 +36,24 @@ JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for Parallel GC\n", value, max_jint); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { +Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // InitialTenuringThreshold is only used for ParallelGC. if (UseParallelGC && (value > MaxTenuringThreshold)) { CommandLineError::print(verbose, "InitialTenuringThreshold (" UINTX_FORMAT ") must be " "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", value, MaxTenuringThreshold); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { +Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // As only ParallelGC uses InitialTenuringThreshold, // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. if (UseParallelGC && (value < InitialTenuringThreshold)) { @@ -61,8 +61,8 @@ JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verb "MaxTenuringThreshold (" UINTX_FORMAT ") must be " "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", value, InitialTenuringThreshold); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } diff --git a/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp b/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp similarity index 84% rename from src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp rename to src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp index b945d8ea3bf..caa82209035 100644 --- a/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp +++ b/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp @@ -29,8 +29,8 @@ #include "utilities/globalDefinitions.hpp" // Parallel Subconstraints -JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose); -JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); -JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); +Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose); +Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); +Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); #endif // SHARE_GC_PARALLEL_COMMANDLINEFLAGCONSTRAINTSPARALLEL_HPP diff --git a/src/hotspot/share/gc/parallel/psMarkSweep.cpp b/src/hotspot/share/gc/parallel/psMarkSweep.cpp index 48456123347..b7f2770f5f3 100644 --- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp +++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp @@ -51,7 +51,6 @@ #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/vmThread.hpp" diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp similarity index 71% rename from src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp rename to src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp index 4378da92890..14491c91645 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp @@ -25,11 +25,11 @@ #include "precompiled.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectorPolicy.hpp" -#include "gc/shared/jvmFlagConstraintsGC.hpp" +#include "gc/shared/commandLineFlagConstraintsGC.hpp" #include "gc/shared/plab.hpp" #include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/thread.inline.hpp" @@ -37,9 +37,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS -#include "gc/cms/jvmFlagConstraintsCMS.hpp" -#include "gc/g1/jvmFlagConstraintsG1.hpp" -#include "gc/parallel/jvmFlagConstraintsParallel.hpp" +#include "gc/cms/commandLineFlagConstraintsCMS.hpp" +#include "gc/g1/commandLineFlagConstraintsG1.hpp" +#include "gc/parallel/commandLineFlagConstraintsParallel.hpp" #endif #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -57,17 +57,17 @@ // the flag has been set by the user and so should be checked. // As ParallelGCThreads differs among GC modes, we need constraint function. -JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { + Flag::Error status = Flag::SUCCESS; #if INCLUDE_ALL_GCS status = ParallelGCThreadsConstraintFuncParallel(value, verbose); - if (status != JVMFlag::SUCCESS) { + if (status != Flag::SUCCESS) { return status; } status = ParallelGCThreadsConstraintFuncCMS(value, verbose); - if (status != JVMFlag::SUCCESS) { + if (status != Flag::SUCCESS) { return status; } #endif @@ -77,7 +77,7 @@ JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { // As ConcGCThreads should be smaller than ParallelGCThreads, // we need constraint function. -JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { #if INCLUDE_ALL_GCS // CMS and G1 GCs use ConcGCThreads. if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) { @@ -85,53 +85,53 @@ JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { "ConcGCThreads (" UINT32_FORMAT ") must be " "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n", value, ParallelGCThreads); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { +static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n", name, value, PLAB::min_size()); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif // INCLUDE_ALL_GCS - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { +Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", name, value, PLAB::max_size()); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif // INCLUDE_ALL_GCS - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -static JVMFlag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - JVMFlag::Error status = MinPLABSizeBounds(name, value, verbose); +static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { + Flag::Error status = MinPLABSizeBounds(name, value, verbose); - if (status == JVMFlag::SUCCESS) { + if (status == Flag::SUCCESS) { return MaxPLABSizeBounds(name, value, verbose); } return status; } -JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); } -JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { @@ -143,98 +143,98 @@ JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { return status; } -JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { +Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { CommandLineError::print(verbose, "MinHeapFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n", value, MaxHeapFreeRatio); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { +Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinHeapFreeRatio) { CommandLineError::print(verbose, "MaxHeapFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n", value, MinHeapFreeRatio); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -static JVMFlag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { +static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) { CommandLineError::print(verbose, "Desired lifetime of SoftReferences cannot be expressed correctly. " "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " "(" INTX_FORMAT ") is too large\n", maxHeap, softRef); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); } -JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { if (value > MarkStackSizeMax) { CommandLineError::print(verbose, "MarkStackSize (" SIZE_FORMAT ") must be " "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n", value, MarkStackSizeMax); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { +Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { CommandLineError::print(verbose, "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n", value, MaxMetaspaceFreeRatio); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { +Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinMetaspaceFreeRatio) { CommandLineError::print(verbose, "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n", value, MinMetaspaceFreeRatio); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { +Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - JVMFlag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose); - if (status != JVMFlag::SUCCESS) { + Flag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose); + if (status != Flag::SUCCESS) { return status; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { +Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - JVMFlag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose); - if (status != JVMFlag::SUCCESS) { + Flag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose); + if (status != Flag::SUCCESS) { return status; } #endif @@ -247,59 +247,59 @@ JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { "AlwaysTenure=%s\n", NeverTenure ? "true" : "false", AlwaysTenure ? "true" : "false"); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - JVMFlag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose); - if (status != JVMFlag::SUCCESS) { + Flag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose); + if (status != Flag::SUCCESS) { return status; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - JVMFlag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose); - if (status != JVMFlag::SUCCESS) { + Flag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose); + if (status != Flag::SUCCESS) { return status; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { size_t aligned_max = align_down(max_uintx/2, Metaspace::reserve_alignment_words()); if (value > aligned_max) { CommandLineError::print(verbose, "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", value, aligned_max); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } // To avoid an overflow by 'align_up(value, alignment)'. -static JVMFlag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { +static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1)); if (value > aligned_max) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", name, value, aligned_max); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { +static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { size_t heap_alignment; #if INCLUDE_ALL_GCS @@ -315,20 +315,20 @@ static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bo return MaxSizeForAlignment(name, value, heap_alignment, verbose); } -JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); } -JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { - JVMFlag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); - if (status == JVMFlag::SUCCESS) { + if (status == Flag::SUCCESS) { status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); } return status; } -JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { +Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) { @@ -336,43 +336,43 @@ JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. " "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n", value, MaxHeapSize, max_uintx); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose); } -JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { #if INCLUDE_ALL_GCS - JVMFlag::Error status = NewSizeConstraintFuncG1(value, verbose); - if (status != JVMFlag::SUCCESS) { + Flag::Error status = NewSizeConstraintFuncG1(value, verbose); + if (status != Flag::SUCCESS) { return status; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { // At least, alignment reserve area is needed. if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { CommandLineError::print(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { CommandLineError::print(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::max_size() * HeapWordSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { // Skip for default value of zero which means set ergonomically. if (FLAG_IS_CMDLINE(TLABSize)) { if (value < MinTLABSize) { @@ -380,22 +380,22 @@ JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { "TLABSize (" SIZE_FORMAT ") must be " "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n", value, MinTLABSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { CommandLineError::print(verbose, "TLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize)); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } // We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(), // so AfterMemoryInit type is enough to check. -JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { +Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { if (UseTLAB) { size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit(); @@ -405,13 +405,13 @@ JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { "TLABWasteIncrement (" UINTX_FORMAT ") must be " "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n", value, (max_uintx - refill_waste_limit)); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { if (FLAG_IS_CMDLINE(SurvivorRatio) && (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) { CommandLineError::print(verbose, @@ -419,52 +419,52 @@ JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", value, (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment())); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value > MaxMetaspaceSize) { CommandLineError::print(verbose, "MetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n", value, MaxMetaspaceSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value < MetaspaceSize) { CommandLineError::print(verbose, "MaxMetaspaceSize (" SIZE_FORMAT ") must be " "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n", value, MaxMetaspaceSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { +Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (value != 0) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (value < ObjectAlignmentInBytes) { CommandLineError::print(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", value, ObjectAlignmentInBytes); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } diff --git a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp new file mode 100644 index 00000000000..dcfaf529c97 --- /dev/null +++ b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP +#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc/cms/commandLineFlagConstraintsCMS.hpp" +#include "gc/g1/commandLineFlagConstraintsG1.hpp" +#include "gc/parallel/commandLineFlagConstraintsParallel.hpp" +#endif + +/* + * Here we have GC arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); +Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); +Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); +Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); +Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); +Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); +Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); + +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose); +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); + +// Internal +Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); + +#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index b14db143052..30754c90a83 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -53,7 +53,6 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp deleted file mode 100644 index b03409c44a3..00000000000 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP -#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc/cms/jvmFlagConstraintsCMS.hpp" -#include "gc/g1/jvmFlagConstraintsG1.hpp" -#include "gc/parallel/jvmFlagConstraintsParallel.hpp" -#endif - -/* - * Here we have GC arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); -JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); -JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); -JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); -JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); -JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); -JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); -JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); -JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); - -JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); -JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); -JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); -JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose); -JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); -JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); -JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); - -// Internal -JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); - -#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 905bab617ca..2bc78f5322f 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -37,7 +37,6 @@ #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/jvmciCodeInstaller.hpp" #include "jvmci/jvmciRuntime.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" @@ -126,7 +125,7 @@ C2V_VMENTRY(jobject, getFlagValue, (JNIEnv *, jobject c2vm, jobject name_handle) } ResourceMark rm; const char* cstring = java_lang_String::as_utf8_string(name()); - JVMFlag* flag = JVMFlag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); + Flag* flag = Flag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); if (flag == NULL) { return c2vm; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 6d9e1d0c4ea..5318b618110 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -29,7 +29,6 @@ #include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/vmStructs_jvmci.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/resourceHash.hpp" @@ -379,9 +378,9 @@ jobjectArray readConfiguration0(JNIEnv *env, TRAPS) { #define COUNT_FLAG(ignore) +1 #ifdef ASSERT #define CHECK_FLAG(type, name) { \ - JVMFlag* flag = JVMFlag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \ + Flag* flag = Flag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \ assert(flag != NULL, "No such flag named " #name); \ - assert(flag->is_##type(), "JVMFlag " #name " is not of type " #type); \ + assert(flag->is_##type(), "Flag " #name " is not of type " #type); \ } #else #define CHECK_FLAG(type, name) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 95d0abfb762..605e203b0fe 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -35,7 +35,6 @@ #include "oops/oop.hpp" #include "oops/oopHandle.hpp" #include "oops/objArrayKlass.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/thread.hpp" @@ -147,16 +146,16 @@ nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ \ - nonstatic_field(ExceptionTableElement, start_pc, u2) \ - nonstatic_field(ExceptionTableElement, end_pc, u2) \ - nonstatic_field(ExceptionTableElement, handler_pc, u2) \ - nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ + nonstatic_field(ExceptionTableElement, start_pc, u2) \ + nonstatic_field(ExceptionTableElement, end_pc, u2) \ + nonstatic_field(ExceptionTableElement, handler_pc, u2) \ + nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ \ - nonstatic_field(JVMFlag, _type, const char*) \ - nonstatic_field(JVMFlag, _name, const char*) \ - unchecked_nonstatic_field(JVMFlag, _addr, sizeof(void*)) \ - nonstatic_field(JVMFlag, _flags, JVMFlag::Flags) \ - static_field(JVMFlag, flags, JVMFlag*) \ + nonstatic_field(Flag, _type, const char*) \ + nonstatic_field(Flag, _name, const char*) \ + unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) \ + nonstatic_field(Flag, _flags, Flag::Flags) \ + static_field(Flag, flags, Flag*) \ \ nonstatic_field(InstanceKlass, _fields, Array*) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ @@ -346,8 +345,8 @@ declare_toplevel_type(BasicLock) \ declare_toplevel_type(CompilerToVM) \ declare_toplevel_type(ExceptionTableElement) \ - declare_toplevel_type(JVMFlag) \ - declare_toplevel_type(JVMFlag*) \ + declare_toplevel_type(Flag) \ + declare_toplevel_type(Flag*) \ declare_toplevel_type(InvocationCounter) \ declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(LocalVariableTableElement) \ diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index a35b1b6a4fd..66da16fabe5 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -63,8 +63,7 @@ #include "prims/resolvedMethodTable.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" -#include "runtime/flags/flagSetting.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" @@ -702,7 +701,7 @@ jint universe_init() { AOTLoader::universe_init(); // Checks 'AfterMemoryInit' constraints. - if (!JVMFlagConstraintList::check_constraints(JVMFlagConstraint::AfterMemoryInit)) { + if (!CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterMemoryInit)) { return JNI_EINVAL; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index a6bcef24b85..40d31912de6 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -38,7 +38,6 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/copy.hpp" diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index 093c344cce0..79753638f77 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -101,7 +101,6 @@ # include "gc/shared/genCollectedHeap.hpp" # include "gc/shared/generation.hpp" # include "gc/shared/generationCounters.hpp" -# include "gc/shared/jvmFlagConstraintsGC.hpp" # include "gc/shared/modRefBarrierSet.hpp" # include "gc/shared/referencePolicy.hpp" # include "gc/shared/referenceProcessor.hpp" @@ -164,13 +163,6 @@ # include "runtime/extendedPC.hpp" # include "runtime/fieldDescriptor.hpp" # include "runtime/fieldType.hpp" -# include "runtime/flags/flagSetting.hpp" -# include "runtime/flags/jvmFlag.hpp" -# include "runtime/flags/jvmFlagConstraintList.hpp" -# include "runtime/flags/jvmFlagConstraintsCompiler.hpp" -# include "runtime/flags/jvmFlagConstraintsRuntime.hpp" -# include "runtime/flags/jvmFlagRangeList.hpp" -# include "runtime/flags/jvmFlagWriteableList.hpp" # include "runtime/frame.hpp" # include "runtime/frame.inline.hpp" # include "runtime/globals.hpp" @@ -300,7 +292,6 @@ # include "gc/cms/concurrentMarkSweepGeneration.hpp" # include "gc/cms/freeChunk.hpp" # include "gc/cms/gSpaceCounters.hpp" -# include "gc/cms/jvmFlagConstraintsCMS.hpp" # include "gc/cms/parOopClosures.hpp" # include "gc/cms/promotionInfo.hpp" # include "gc/cms/yieldingWorkgroup.hpp" @@ -308,12 +299,10 @@ # include "gc/g1/g1BlockOffsetTable.hpp" # include "gc/g1/g1OopClosures.hpp" # include "gc/g1/g1_globals.hpp" -# include "gc/g1/jvmFlagConstraintsG1.hpp" # include "gc/g1/ptrQueue.hpp" # include "gc/g1/satbMarkQueue.hpp" # include "gc/parallel/gcAdaptivePolicyCounters.hpp" # include "gc/parallel/immutableSpace.hpp" -# include "gc/parallel/jvmFlagConstraintsParallel.hpp" # include "gc/parallel/mutableSpace.hpp" # include "gc/parallel/objectStartArray.hpp" # include "gc/parallel/parMarkBitMap.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 3646046a00b..44913f41868 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -53,7 +53,6 @@ #include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -972,29 +971,29 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) WB_END template -static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, JVMFlag::Error (*TAt)(const char*, T*, bool, bool)) { +static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAt)(const char*, T*, bool, bool)) { if (name == NULL) { return false; } ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); - JVMFlag::Error result = (*TAt)(flag_name, value, true, true); + Flag::Error result = (*TAt)(flag_name, value, true, true); env->ReleaseStringUTFChars(name, flag_name); - return (result == JVMFlag::SUCCESS); + return (result == Flag::SUCCESS); } template -static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, JVMFlag::Error (*TAtPut)(const char*, T*, JVMFlag::Flags)) { +static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAtPut)(const char*, T*, Flag::Flags)) { if (name == NULL) { return false; } ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); - JVMFlag::Error result = (*TAtPut)(flag_name, value, JVMFlag::INTERNAL); + Flag::Error result = (*TAtPut)(flag_name, value, Flag::INTERNAL); env->ReleaseStringUTFChars(name, flag_name); - return (result == JVMFlag::SUCCESS); + return (result == Flag::SUCCESS); } template @@ -1027,28 +1026,28 @@ static jobject doubleBox(JavaThread* thread, JNIEnv* env, jdouble value) { return box(thread, env, vmSymbols::java_lang_Double(), vmSymbols::Double_valueOf_signature(), value); } -static JVMFlag* getVMFlag(JavaThread* thread, JNIEnv* env, jstring name) { +static Flag* getVMFlag(JavaThread* thread, JNIEnv* env, jstring name) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, NULL); - JVMFlag* result = JVMFlag::find_flag(flag_name, strlen(flag_name), true, true); + Flag* result = Flag::find_flag(flag_name, strlen(flag_name), true, true); env->ReleaseStringUTFChars(name, flag_name); return result; } WB_ENTRY(jboolean, WB_IsConstantVMFlag(JNIEnv* env, jobject o, jstring name)) - JVMFlag* flag = getVMFlag(thread, env, name); + Flag* flag = getVMFlag(thread, env, name); return (flag != NULL) && flag->is_constant_in_binary(); WB_END WB_ENTRY(jboolean, WB_IsLockedVMFlag(JNIEnv* env, jobject o, jstring name)) - JVMFlag* flag = getVMFlag(thread, env, name); + Flag* flag = getVMFlag(thread, env, name); return (flag != NULL) && !(flag->is_unlocked() || flag->is_unlocker()); WB_END WB_ENTRY(jobject, WB_GetBooleanVMFlag(JNIEnv* env, jobject o, jstring name)) bool result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::boolAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::boolAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return booleanBox(thread, env, result); } @@ -1057,7 +1056,7 @@ WB_END WB_ENTRY(jobject, WB_GetIntVMFlag(JNIEnv* env, jobject o, jstring name)) int result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::intAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::intAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1066,7 +1065,7 @@ WB_END WB_ENTRY(jobject, WB_GetUintVMFlag(JNIEnv* env, jobject o, jstring name)) uint result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::uintAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uintAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1075,7 +1074,7 @@ WB_END WB_ENTRY(jobject, WB_GetIntxVMFlag(JNIEnv* env, jobject o, jstring name)) intx result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::intxAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::intxAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1084,7 +1083,7 @@ WB_END WB_ENTRY(jobject, WB_GetUintxVMFlag(JNIEnv* env, jobject o, jstring name)) uintx result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::uintxAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uintxAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1093,7 +1092,7 @@ WB_END WB_ENTRY(jobject, WB_GetUint64VMFlag(JNIEnv* env, jobject o, jstring name)) uint64_t result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::uint64_tAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1102,7 +1101,7 @@ WB_END WB_ENTRY(jobject, WB_GetSizeTVMFlag(JNIEnv* env, jobject o, jstring name)) uintx result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::size_tAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1111,7 +1110,7 @@ WB_END WB_ENTRY(jobject, WB_GetDoubleVMFlag(JNIEnv* env, jobject o, jstring name)) double result; - if (GetVMFlag (thread, env, name, &result, &JVMFlag::doubleAt)) { + if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return doubleBox(thread, env, result); } @@ -1120,7 +1119,7 @@ WB_END WB_ENTRY(jstring, WB_GetStringVMFlag(JNIEnv* env, jobject o, jstring name)) ccstr ccstrResult; - if (GetVMFlag (thread, env, name, &ccstrResult, &JVMFlag::ccstrAt)) { + if (GetVMFlag (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI jstring result = env->NewStringUTF(ccstrResult); CHECK_JNI_EXCEPTION_(env, NULL); @@ -1131,42 +1130,42 @@ WB_END WB_ENTRY(void, WB_SetBooleanVMFlag(JNIEnv* env, jobject o, jstring name, jboolean value)) bool result = value == JNI_TRUE ? true : false; - SetVMFlag (thread, env, name, &result, &JVMFlag::boolAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::boolAtPut); WB_END WB_ENTRY(void, WB_SetIntVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) int result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::intAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::intAtPut); WB_END WB_ENTRY(void, WB_SetUintVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uint result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::uintAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::uintAtPut); WB_END WB_ENTRY(void, WB_SetIntxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) intx result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::intxAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::intxAtPut); WB_END WB_ENTRY(void, WB_SetUintxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uintx result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::uintxAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::uintxAtPut); WB_END WB_ENTRY(void, WB_SetUint64VMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uint64_t result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::uint64_tAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAtPut); WB_END WB_ENTRY(void, WB_SetSizeTVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) size_t result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::size_tAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAtPut); WB_END WB_ENTRY(void, WB_SetDoubleVMFlag(JNIEnv* env, jobject o, jstring name, jdouble value)) double result = value; - SetVMFlag (thread, env, name, &result, &JVMFlag::doubleAtPut); + SetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAtPut); WB_END WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring value)) @@ -1183,7 +1182,7 @@ WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring bool needFree; { ThreadInVMfromNative ttvfn(thread); // back to VM - needFree = SetVMFlag (thread, env, name, &ccstrResult, &JVMFlag::ccstrAtPut); + needFree = SetVMFlag (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAtPut); } if (value != NULL) { env->ReleaseStringUTFChars(value, ccstrValue); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 1e49fe1d35d..874c86a018d 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -42,10 +42,10 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/arguments_ext.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" -#include "runtime/flags/jvmFlagWriteableList.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/commandLineFlagWriteableList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "runtime/os.inline.hpp" @@ -739,7 +739,7 @@ static bool verify_special_jvm_flags() { // if flag has become obsolete it should not have a "globals" flag defined anymore. if (!version_less_than(JDK_Version::current(), flag.obsolete_in)) { - if (JVMFlag::find_flag(flag.name) != NULL) { + if (Flag::find_flag(flag.name) != NULL) { // Temporarily disable the warning: 8196739 // warning("Global variable for obsolete special flag entry \"%s\" should be removed", flag.name); } @@ -749,7 +749,7 @@ static bool verify_special_jvm_flags() { if (!flag.expired_in.is_undefined()) { // if flag has become expired it should not have a "globals" flag defined anymore. if (!version_less_than(JDK_Version::current(), flag.expired_in)) { - if (JVMFlag::find_flag(flag.name) != NULL) { + if (Flag::find_flag(flag.name) != NULL) { // Temporarily disable the warning: 8196739 // warning("Global variable for expired flag entry \"%s\" should be removed", flag.name); } @@ -833,15 +833,15 @@ void Arguments::describe_range_error(ArgsRange errcode) { } } -static bool set_bool_flag(const char* name, bool value, JVMFlag::Flags origin) { - if (JVMFlag::boolAtPut(name, &value, origin) == JVMFlag::SUCCESS) { +static bool set_bool_flag(const char* name, bool value, Flag::Flags origin) { + if (CommandLineFlags::boolAtPut(name, &value, origin) == Flag::SUCCESS) { return true; } else { return false; } } -static bool set_fp_numeric_flag(const char* name, char* value, JVMFlag::Flags origin) { +static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origin) { char* end; errno = 0; double v = strtod(value, &end); @@ -849,18 +849,18 @@ static bool set_fp_numeric_flag(const char* name, char* value, JVMFlag::Flags or return false; } - if (JVMFlag::doubleAtPut(name, &v, origin) == JVMFlag::SUCCESS) { + if (CommandLineFlags::doubleAtPut(name, &v, origin) == Flag::SUCCESS) { return true; } return false; } -static bool set_numeric_flag(const char* name, char* value, JVMFlag::Flags origin) { +static bool set_numeric_flag(const char* name, char* value, Flag::Flags origin) { julong v; int int_v; intx intx_v; bool is_neg = false; - JVMFlag* result = JVMFlag::find_flag(name, strlen(name)); + Flag* result = Flag::find_flag(name, strlen(name)); if (result == NULL) { return false; @@ -882,43 +882,43 @@ static bool set_numeric_flag(const char* name, char* value, JVMFlag::Flags origi if (is_neg) { int_v = -int_v; } - return JVMFlag::intAtPut(result, &int_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::intAtPut(result, &int_v, origin) == Flag::SUCCESS; } else if (result->is_uint()) { uint uint_v = (uint) v; - return JVMFlag::uintAtPut(result, &uint_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::uintAtPut(result, &uint_v, origin) == Flag::SUCCESS; } else if (result->is_intx()) { intx_v = (intx) v; if (is_neg) { intx_v = -intx_v; } - return JVMFlag::intxAtPut(result, &intx_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::intxAtPut(result, &intx_v, origin) == Flag::SUCCESS; } else if (result->is_uintx()) { uintx uintx_v = (uintx) v; - return JVMFlag::uintxAtPut(result, &uintx_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::uintxAtPut(result, &uintx_v, origin) == Flag::SUCCESS; } else if (result->is_uint64_t()) { uint64_t uint64_t_v = (uint64_t) v; - return JVMFlag::uint64_tAtPut(result, &uint64_t_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::uint64_tAtPut(result, &uint64_t_v, origin) == Flag::SUCCESS; } else if (result->is_size_t()) { size_t size_t_v = (size_t) v; - return JVMFlag::size_tAtPut(result, &size_t_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::size_tAtPut(result, &size_t_v, origin) == Flag::SUCCESS; } else if (result->is_double()) { double double_v = (double) v; - return JVMFlag::doubleAtPut(result, &double_v, origin) == JVMFlag::SUCCESS; + return CommandLineFlags::doubleAtPut(result, &double_v, origin) == Flag::SUCCESS; } else { return false; } } -static bool set_string_flag(const char* name, const char* value, JVMFlag::Flags origin) { - if (JVMFlag::ccstrAtPut(name, &value, origin) != JVMFlag::SUCCESS) return false; - // Contract: JVMFlag always returns a pointer that needs freeing. +static bool set_string_flag(const char* name, const char* value, Flag::Flags origin) { + if (CommandLineFlags::ccstrAtPut(name, &value, origin) != Flag::SUCCESS) return false; + // Contract: CommandLineFlags always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); return true; } -static bool append_to_string_flag(const char* name, const char* new_value, JVMFlag::Flags origin) { +static bool append_to_string_flag(const char* name, const char* new_value, Flag::Flags origin) { const char* old_value = ""; - if (JVMFlag::ccstrAt(name, &old_value) != JVMFlag::SUCCESS) return false; + if (CommandLineFlags::ccstrAt(name, &old_value) != Flag::SUCCESS) return false; size_t old_len = old_value != NULL ? strlen(old_value) : 0; size_t new_len = strlen(new_value); const char* value; @@ -935,11 +935,11 @@ static bool append_to_string_flag(const char* name, const char* new_value, JVMFl value = buf; free_this_too = buf; } - (void) JVMFlag::ccstrAtPut(name, &value, origin); - // JVMFlag always returns a pointer that needs freeing. + (void) CommandLineFlags::ccstrAtPut(name, &value, origin); + // CommandLineFlags always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); if (free_this_too != NULL) { - // JVMFlag made its own copy, so I must delete my own temp. buffer. + // CommandLineFlags made its own copy, so I must delete my own temp. buffer. FREE_C_HEAP_ARRAY(char, free_this_too); } return true; @@ -1010,7 +1010,7 @@ AliasedLoggingFlag Arguments::catch_logging_aliases(const char* name, bool on){ return a; } -bool Arguments::parse_argument(const char* arg, JVMFlag::Flags origin) { +bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { // range of acceptable characters spelled out for portability reasons #define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]" @@ -1048,7 +1048,7 @@ bool Arguments::parse_argument(const char* arg, JVMFlag::Flags origin) { char punct; if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "%c", name, &punct) == 2 && punct == '=') { const char* value = strchr(arg, '=') + 1; - JVMFlag* flag; + Flag* flag; // this scanf pattern matches both strings (handled here) and numbers (handled later)) AliasedLoggingFlag alf = catch_logging_aliases(name, true); @@ -1060,7 +1060,7 @@ bool Arguments::parse_argument(const char* arg, JVMFlag::Flags origin) { if (real_name == NULL) { return false; } - flag = JVMFlag::find_flag(real_name); + flag = Flag::find_flag(real_name); if (flag != NULL && flag->is_ccstr()) { if (flag->ccstr_accumulates()) { return append_to_string_flag(real_name, value, origin); @@ -1221,7 +1221,7 @@ void Arguments::print_jvm_args_on(outputStream* st) { bool Arguments::process_argument(const char* arg, jboolean ignore_unrecognized, - JVMFlag::Flags origin) { + Flag::Flags origin) { JDK_Version since = JDK_Version(); if (parse_argument(arg, origin)) { @@ -1266,10 +1266,10 @@ bool Arguments::process_argument(const char* arg, // For locked flags, report a custom error message if available. // Otherwise, report the standard unrecognized VM option. - JVMFlag* found_flag = JVMFlag::find_flag((const char*)argname, arg_len, true, true); + Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true, true); if (found_flag != NULL) { char locked_message_buf[BUFLEN]; - JVMFlag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN); + Flag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN); if (strlen(locked_message_buf) == 0) { if (found_flag->is_bool() && !has_plus_minus) { jio_fprintf(defaultStream::error_stream(), @@ -1283,8 +1283,8 @@ bool Arguments::process_argument(const char* arg, } } else { #ifdef PRODUCT - bool mismatched = ((msg_type == JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) || - (msg_type == JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD)); + bool mismatched = ((msg_type == Flag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) || + (msg_type == Flag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD)); if (ignore_unrecognized && mismatched) { return true; } @@ -1297,7 +1297,7 @@ bool Arguments::process_argument(const char* arg, } jio_fprintf(defaultStream::error_stream(), "Unrecognized VM option '%s'\n", argname); - JVMFlag* fuzzy_matched = JVMFlag::fuzzy_match((const char*)argname, arg_len, true); + Flag* fuzzy_matched = Flag::fuzzy_match((const char*)argname, arg_len, true); if (fuzzy_matched != NULL) { jio_fprintf(defaultStream::error_stream(), "Did you mean '%s%s%s'? ", @@ -1350,7 +1350,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, // this allows a way to include spaces in string-valued options token[pos] = '\0'; logOption(token); - result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); build_jvm_flags(token); pos = 0; in_white_space = true; @@ -1368,7 +1368,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } if (pos > 0) { token[pos] = '\0'; - result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); build_jvm_flags(token); } fclose(stream); @@ -1991,10 +1991,10 @@ jint Arguments::set_aggressive_heap_flags() { initHeapSize = limit_by_allocatable_memory(initHeapSize); if (FLAG_IS_DEFAULT(MaxHeapSize)) { - if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != Flag::SUCCESS) { return JNI_EINVAL; } // Currently the minimum size and the initial heap sizes are the same. @@ -2003,10 +2003,10 @@ jint Arguments::set_aggressive_heap_flags() { if (FLAG_IS_DEFAULT(NewSize)) { // Make the young generation 3/8ths of the total heap. if (FLAG_SET_CMDLINE(size_t, NewSize, - ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != JVMFlag::SUCCESS) { + ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != Flag::SUCCESS) { return JNI_EINVAL; } } @@ -2016,20 +2016,20 @@ jint Arguments::set_aggressive_heap_flags() { #endif // Increase some data structure sizes for efficiency - if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != Flag::SUCCESS) { return JNI_EINVAL; } // See the OldPLABSize comment below, but replace 'after promotion' // with 'after copying'. YoungPLABSize is the size of the survivor // space per-gc-thread buffers. The default is 4kw. - if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != JVMFlag::SUCCESS) { // Note: this is in words + if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != Flag::SUCCESS) { // Note: this is in words return JNI_EINVAL; } @@ -2046,29 +2046,29 @@ jint Arguments::set_aggressive_heap_flags() { // locality. A minor effect may be that larger PLABs reduce the // number of PLAB allocation events during gc. The value of 8kw // was arrived at by experimenting with specjbb. - if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != JVMFlag::SUCCESS) { // Note: this is in words + if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != Flag::SUCCESS) { // Note: this is in words return JNI_EINVAL; } // Enable parallel GC and adaptive generation sizing - if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != Flag::SUCCESS) { return JNI_EINVAL; } // Encourage steady state memory management - if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != Flag::SUCCESS) { return JNI_EINVAL; } // This appears to improve mutator locality - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { return JNI_EINVAL; } // Get around early Solaris scheduling bug // (affinity vs other jobs on system) // but disallow DR and offlining (5008695). - if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != Flag::SUCCESS) { return JNI_EINVAL; } @@ -2409,20 +2409,20 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, // Parse args structure generated from JAVA_TOOL_OPTIONS environment // variable (if present). - jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); + jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Parse args structure generated from the command line flags. - result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, JVMFlag::COMMAND_LINE); + result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, Flag::COMMAND_LINE); if (result != JNI_OK) { return result; } // Parse args structure generated from the _JAVA_OPTIONS environment // variable (if present) (mimics classic VM) - result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); + result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); if (result != JNI_OK) { return result; } @@ -2566,7 +2566,7 @@ jint Arguments::parse_xss(const JavaVMOption* option, const char* tail, intx* ou return JNI_OK; } -jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin) { +jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin) { // For match_option to return remaining or value part of option string const char* tail; @@ -2599,7 +2599,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m } else if (!strcmp(tail, ":gc")) { LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc)); } else if (!strcmp(tail, ":jni")) { - if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != Flag::SUCCESS) { return JNI_EINVAL; } } @@ -2736,24 +2736,24 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_enable_preview(); // -Xnoclassgc } else if (match_option(option, "-Xnoclassgc")) { - if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xconcgc } else if (match_option(option, "-Xconcgc")) { - if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != Flag::SUCCESS) { return JNI_EINVAL; } handle_extra_cms_flags("-Xconcgc uses UseConcMarkSweepGC"); // -Xnoconcgc } else if (match_option(option, "-Xnoconcgc")) { - if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != Flag::SUCCESS) { return JNI_EINVAL; } handle_extra_cms_flags("-Xnoconcgc uses UseConcMarkSweepGC"); // -Xbatch } else if (match_option(option, "-Xbatch")) { - if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xmn for compatibility with other JVM vendors @@ -2766,10 +2766,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m describe_range_error(errcode); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xms @@ -2786,7 +2786,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_min_heap_size((size_t)long_initial_heap_size); // Currently the minimum size and the initial heap sizes are the same. // Can be overridden with -XX:InitialHeapSize. - if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xmx @@ -2799,7 +2799,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m describe_range_error(errcode); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != Flag::SUCCESS) { return JNI_EINVAL; } // Xmaxf @@ -2812,7 +2812,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m option->optionString); return JNI_EINVAL; } else { - if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != Flag::SUCCESS) { return JNI_EINVAL; } } @@ -2826,7 +2826,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m option->optionString); return JNI_EINVAL; } else { - if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != Flag::SUCCESS) { return JNI_EINVAL; } } @@ -2837,7 +2837,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m if (err != JNI_OK) { return err; } - if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-Xmaxjitcodesize", &tail) || @@ -2850,7 +2850,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m "Invalid maximum code cache size: %s.\n", option->optionString); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != Flag::SUCCESS) { return JNI_EINVAL; } // -green @@ -2864,7 +2864,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xrs } else if (match_option(option, "-Xrs")) { // Classic/EVM option, new functionality - if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xprof @@ -2875,17 +2875,17 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m warning("Ignoring option %s; support was removed in %s", option->optionString, version); // -Xconcurrentio } else if (match_option(option, "-Xconcurrentio")) { - if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) { return JNI_EINVAL; } SafepointSynchronize::set_defer_thr_suspend_loop_count(); - if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != JVMFlag::SUCCESS) { // 20Kb per thread added to new generation + if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != Flag::SUCCESS) { // 20Kb per thread added to new generation return JNI_EINVAL; } @@ -2897,7 +2897,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m #ifndef PRODUCT // -Xprintflags } else if (match_option(option, "-Xprintflags")) { - JVMFlag::printFlags(tty, false); + CommandLineFlags::printFlags(tty, false); vm_exit(0); #endif // -D @@ -2932,7 +2932,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // Out of the box management support if (match_option(option, "-Dcom.sun.management", &tail)) { #if INCLUDE_MANAGEMENT - if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != Flag::SUCCESS) { return JNI_EINVAL; } // management agent in module jdk.management.agent @@ -2957,55 +2957,55 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_mode_flags(_comp); // -Xshare:dump } else if (match_option(option, "-Xshare:dump")) { - if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } set_mode_flags(_int); // Prevent compilation, which creates objects // -Xshare:on } else if (match_option(option, "-Xshare:on")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xshare:auto } else if (match_option(option, "-Xshare:auto")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xshare:off } else if (match_option(option, "-Xshare:off")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) { return JNI_EINVAL; } // -Xverify } else if (match_option(option, "-Xverify", &tail)) { if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (strcmp(tail, ":remote") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (strcmp(tail, ":none") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (is_bad_option(option, args->ignoreUnrecognized, "verification")) { @@ -3064,23 +3064,23 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure; // and the last option wins. } else if (match_option(option, "-XX:+NeverTenure")) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+AlwaysTenure")) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) { @@ -3091,51 +3091,51 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != Flag::SUCCESS) { return JNI_EINVAL; } if (MaxTenuringThreshold == 0) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) { return JNI_EINVAL; } } else { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) { return JNI_EINVAL; } } } else if (match_option(option, "-XX:+DisplayVMOutputToStderr")) { - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+DisplayVMOutputToStdout")) { - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != Flag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+ExtendedDTraceProbes")) { #if defined(DTRACE_ENABLED) - if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != Flag::SUCCESS) { return JNI_EINVAL; } #else // defined(DTRACE_ENABLED) @@ -3145,11 +3145,11 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m #endif // defined(DTRACE_ENABLED) #ifdef ASSERT } else if (match_option(option, "-XX:+FullGCALot")) { - if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != Flag::SUCCESS) { return JNI_EINVAL; } // disable scavenge before parallel mark-compact - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { return JNI_EINVAL; } #endif @@ -3178,10 +3178,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xshare:on // -Xlog:class+path=info if (PrintSharedArchiveAndExit) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(class, path)); @@ -3856,7 +3856,7 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, continue; } if (match_option(option, "-XX:+PrintFlagsInitial")) { - JVMFlag::printFlags(tty, false); + CommandLineFlags::printFlags(tty, false); vm_exit(0); } if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { @@ -3885,13 +3885,13 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, #ifndef PRODUCT if (match_option(option, "-XX:+PrintFlagsWithComments")) { - JVMFlag::printFlags(tty, true); + CommandLineFlags::printFlags(tty, true); vm_exit(0); } #endif if (match_option(option, "-XX:+UseAppCDS")) { - JVMFlag* flag = JVMFlag::find_flag("SharedArchiveFile", 17, true, true); + Flag* flag = Flag::find_flag("SharedArchiveFile", 17, true, true); if (flag->is_diagnostic()) { flag->clear_diagnostic(); } @@ -3947,9 +3947,9 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { assert(verify_special_jvm_flags(), "deprecated and obsolete flag table inconsistent"); // Initialize ranges, constraints and writeables - JVMFlagRangeList::init(); - JVMFlagConstraintList::init(); - JVMFlagWriteableList::init(); + CommandLineFlagRangeList::init(); + CommandLineFlagConstraintList::init(); + CommandLineFlagWriteableList::init(); // If flag "-XX:Flags=flags-file" is used it will be the first option to be processed. const char* hotspotrc = ".hotspotrc"; @@ -4250,7 +4250,7 @@ jint Arguments::apply_ergo() { #endif // PRODUCT if (PrintCommandLineFlags) { - JVMFlag::printSetFlags(tty); + CommandLineFlags::printSetFlags(tty); } // Apply CPU specific policy for the BiasedLocking diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index edf88193673..83dd78fff81 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -28,7 +28,6 @@ #include "logging/logLevel.hpp" #include "logging/logTag.hpp" #include "memory/allocation.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" @@ -414,8 +413,8 @@ class Arguments : AllStatic { // Argument parsing static void do_pd_flag_adjustments(); - static bool parse_argument(const char* arg, JVMFlag::Flags origin); - static bool process_argument(const char* arg, jboolean ignore_unrecognized, JVMFlag::Flags origin); + static bool parse_argument(const char* arg, Flag::Flags origin); + static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin); static void process_java_launcher_argument(const char*, void*); static void process_java_compiler_argument(const char* arg); static jint parse_options_environment_variable(const char* name, ScopedVMInitArgs* vm_args); @@ -443,7 +442,7 @@ class Arguments : AllStatic { static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin); static jint finalize_vm_init_args(bool patch_mod_javabase); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp b/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp similarity index 58% rename from src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp rename to src/hotspot/share/runtime/commandLineFlagConstraintList.cpp index a0832397585..c900c2e4e1a 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp +++ b/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp @@ -25,12 +25,11 @@ #include "precompiled.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" -#include "gc/shared/jvmFlagConstraintsGC.hpp" +#include "gc/shared/commandLineFlagConstraintsGC.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" -#include "runtime/flags/jvmFlagConstraintsCompiler.hpp" -#include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/commandLineFlagConstraintsCompiler.hpp" +#include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" #ifdef COMPILER1 @@ -40,161 +39,162 @@ #include "opto/c2_globals.hpp" #endif -class JVMFlagConstraint_bool : public JVMFlagConstraint { - JVMFlagConstraintFunc_bool _constraint; + +class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_bool _constraint; const bool* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_bool(const char* name, const bool* ptr, - JVMFlagConstraintFunc_bool func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_bool(const char* name, const bool* ptr, + CommandLineFlagConstraintFunc_bool func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { bool value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_bool(bool value, bool verbose) { + Flag::Error apply_bool(bool value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_int : public JVMFlagConstraint { - JVMFlagConstraintFunc_int _constraint; +class CommandLineFlagConstraint_int : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_int _constraint; const int* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_int(const char* name, const int* ptr, - JVMFlagConstraintFunc_int func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_int(const char* name, const int* ptr, + CommandLineFlagConstraintFunc_int func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { int value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_int(int value, bool verbose) { + Flag::Error apply_int(int value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_intx : public JVMFlagConstraint { - JVMFlagConstraintFunc_intx _constraint; +class CommandLineFlagConstraint_intx : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_intx _constraint; const intx* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_intx(const char* name, const intx* ptr, - JVMFlagConstraintFunc_intx func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_intx(const char* name, const intx* ptr, + CommandLineFlagConstraintFunc_intx func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { intx value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_intx(intx value, bool verbose) { + Flag::Error apply_intx(intx value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_uint : public JVMFlagConstraint { - JVMFlagConstraintFunc_uint _constraint; +class CommandLineFlagConstraint_uint : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_uint _constraint; const uint* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_uint(const char* name, const uint* ptr, - JVMFlagConstraintFunc_uint func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_uint(const char* name, const uint* ptr, + CommandLineFlagConstraintFunc_uint func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { uint value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_uint(uint value, bool verbose) { + Flag::Error apply_uint(uint value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_uintx : public JVMFlagConstraint { - JVMFlagConstraintFunc_uintx _constraint; +class CommandLineFlagConstraint_uintx : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_uintx _constraint; const uintx* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_uintx(const char* name, const uintx* ptr, - JVMFlagConstraintFunc_uintx func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_uintx(const char* name, const uintx* ptr, + CommandLineFlagConstraintFunc_uintx func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { uintx value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_uintx(uintx value, bool verbose) { + Flag::Error apply_uintx(uintx value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_uint64_t : public JVMFlagConstraint { - JVMFlagConstraintFunc_uint64_t _constraint; +class CommandLineFlagConstraint_uint64_t : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_uint64_t _constraint; const uint64_t* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_uint64_t(const char* name, const uint64_t* ptr, - JVMFlagConstraintFunc_uint64_t func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_uint64_t(const char* name, const uint64_t* ptr, + CommandLineFlagConstraintFunc_uint64_t func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { uint64_t value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_uint64_t(uint64_t value, bool verbose) { + Flag::Error apply_uint64_t(uint64_t value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_size_t : public JVMFlagConstraint { - JVMFlagConstraintFunc_size_t _constraint; +class CommandLineFlagConstraint_size_t : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_size_t _constraint; const size_t* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_size_t(const char* name, const size_t* ptr, - JVMFlagConstraintFunc_size_t func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_size_t(const char* name, const size_t* ptr, + CommandLineFlagConstraintFunc_size_t func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { size_t value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_size_t(size_t value, bool verbose) { + Flag::Error apply_size_t(size_t value, bool verbose) { return _constraint(value, verbose); } }; -class JVMFlagConstraint_double : public JVMFlagConstraint { - JVMFlagConstraintFunc_double _constraint; +class CommandLineFlagConstraint_double : public CommandLineFlagConstraint { + CommandLineFlagConstraintFunc_double _constraint; const double* _ptr; public: // the "name" argument must be a string literal - JVMFlagConstraint_double(const char* name, const double* ptr, - JVMFlagConstraintFunc_double func, - ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + CommandLineFlagConstraint_double(const char* name, const double* ptr, + CommandLineFlagConstraintFunc_double func, + ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - JVMFlag::Error apply(bool verbose) { + Flag::Error apply(bool verbose) { double value = *_ptr; return _constraint(value, verbose); } - JVMFlag::Error apply_double(double value, bool verbose) { + Flag::Error apply_double(double value, bool verbose) { return _constraint(value, verbose); } }; @@ -214,30 +214,30 @@ void emit_constraint_uint64_t(const char* /*name*/, const uint64_t* /*value*/) void emit_constraint_size_t(const char* /*name*/, const size_t* /*value*/) { /* NOP */ } void emit_constraint_double(const char* /*name*/, const double* /*value*/) { /* NOP */ } -// JVMFlagConstraint emitting code functions if function argument is provided -void emit_constraint_bool(const char* name, const bool* ptr, JVMFlagConstraintFunc_bool func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_bool(name, ptr, func, type)); +// CommandLineFlagConstraint emitting code functions if function argument is provided +void emit_constraint_bool(const char* name, const bool* ptr, CommandLineFlagConstraintFunc_bool func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_bool(name, ptr, func, type)); } -void emit_constraint_int(const char* name, const int* ptr, JVMFlagConstraintFunc_int func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_int(name, ptr, func, type)); +void emit_constraint_int(const char* name, const int* ptr, CommandLineFlagConstraintFunc_int func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_int(name, ptr, func, type)); } -void emit_constraint_intx(const char* name, const intx* ptr, JVMFlagConstraintFunc_intx func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_intx(name, ptr, func, type)); +void emit_constraint_intx(const char* name, const intx* ptr, CommandLineFlagConstraintFunc_intx func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_intx(name, ptr, func, type)); } -void emit_constraint_uint(const char* name, const uint* ptr, JVMFlagConstraintFunc_uint func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_uint(name, ptr, func, type)); +void emit_constraint_uint(const char* name, const uint* ptr, CommandLineFlagConstraintFunc_uint func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint(name, ptr, func, type)); } -void emit_constraint_uintx(const char* name, const uintx* ptr, JVMFlagConstraintFunc_uintx func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_uintx(name, ptr, func, type)); +void emit_constraint_uintx(const char* name, const uintx* ptr, CommandLineFlagConstraintFunc_uintx func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uintx(name, ptr, func, type)); } -void emit_constraint_uint64_t(const char* name, const uint64_t* ptr, JVMFlagConstraintFunc_uint64_t func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_uint64_t(name, ptr, func, type)); +void emit_constraint_uint64_t(const char* name, const uint64_t* ptr, CommandLineFlagConstraintFunc_uint64_t func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint64_t(name, ptr, func, type)); } -void emit_constraint_size_t(const char* name, const size_t* ptr, JVMFlagConstraintFunc_size_t func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_size_t(name, ptr, func, type)); +void emit_constraint_size_t(const char* name, const size_t* ptr, CommandLineFlagConstraintFunc_size_t func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_size_t(name, ptr, func, type)); } -void emit_constraint_double(const char* name, const double* ptr, JVMFlagConstraintFunc_double func, JVMFlagConstraint::ConstraintType type) { - JVMFlagConstraintList::add(new JVMFlagConstraint_double(name, ptr, func, type)); +void emit_constraint_double(const char* name, const double* ptr, CommandLineFlagConstraintFunc_double func, CommandLineFlagConstraint::ConstraintType type) { + CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_double(name, ptr, func, type)); } // Generate code to call emit_constraint_xxx function @@ -265,16 +265,16 @@ void emit_constraint_double(const char* name, const double* ptr, JVMFlagConstrai #endif // Generate func argument to pass into emit_constraint_xxx functions -#define EMIT_CONSTRAINT_CHECK(func, type) , func, JVMFlagConstraint::type +#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type // the "name" argument must be a string literal #define INITIAL_CONSTRAINTS_SIZE 72 -GrowableArray* JVMFlagConstraintList::_constraints = NULL; -JVMFlagConstraint::ConstraintType JVMFlagConstraintList::_validating_type = JVMFlagConstraint::AtParse; +GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; +CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; // Check the ranges of all flags that have them or print them out and exit if requested -void JVMFlagConstraintList::init(void) { - _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); +void CommandLineFlagConstraintList::init(void) { + _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); emit_constraint_no(NULL VM_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, @@ -331,10 +331,10 @@ void JVMFlagConstraintList::init(void) { #endif // COMPILER2 } -JVMFlagConstraint* JVMFlagConstraintList::find(const char* name) { - JVMFlagConstraint* found = NULL; +CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) { + CommandLineFlagConstraint* found = NULL; for (int i=0; iname(), name) == 0) { found = constraint; break; @@ -344,9 +344,9 @@ JVMFlagConstraint* JVMFlagConstraintList::find(const char* name) { } // Find constraints by name and return only if found constraint's type is equal or lower than current validating type. -JVMFlagConstraint* JVMFlagConstraintList::find_if_needs_check(const char* name) { - JVMFlagConstraint* found = NULL; - JVMFlagConstraint* constraint = find(name); +CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(const char* name) { + CommandLineFlagConstraint* found = NULL; + CommandLineFlagConstraint* constraint = find(name); if (constraint && (constraint->type() <= _validating_type)) { found = constraint; } @@ -354,15 +354,15 @@ JVMFlagConstraint* JVMFlagConstraintList::find_if_needs_check(const char* name) } // Check constraints for specific constraint type. -bool JVMFlagConstraintList::check_constraints(JVMFlagConstraint::ConstraintType type) { +bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { guarantee(type > _validating_type, "Constraint check is out of order."); _validating_type = type; bool status = true; for (int i=0; itype()) continue; - if (constraint->apply(true) != JVMFlag::SUCCESS) status = false; + if (constraint->apply(true) != Flag::SUCCESS) status = false; } return status; } diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp new file mode 100644 index 00000000000..6700bb1da4d --- /dev/null +++ b/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP +#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP + +#include "runtime/globals.hpp" +#include "utilities/growableArray.hpp" + +/* + * Here we have a mechanism for extracting constraints (as custom functions) for flags, + * which otherwise can not be expressed via simple range check, specified in flag macro tables. + * + * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change. + * + * See runtime "runtime/commandLineFlagConstraintsCompiler.hpp", + * "runtime/commandLineFlagConstraintsGC.hpp" and + * "runtime/commandLineFlagConstraintsRuntime.hpp" for the functions themselves. + */ + +typedef Flag::Error (*CommandLineFlagConstraintFunc_bool)(bool value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_int)(int value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_intx)(intx value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_uint)(uint value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_uintx)(uintx value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(size_t value, bool verbose); +typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(double value, bool verbose); + +class CommandLineFlagConstraint : public CHeapObj { +public: + // During VM initialization, constraint validation will be done order of ConstraintType. + enum ConstraintType { + // Will be validated during argument processing (Arguments::parse_argument). + AtParse = 0, + // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). + AfterErgo = 1, + // Will be validated inside universe_init(), right after Metaspace::global_initialize(). + AfterMemoryInit = 2 + }; + +private: + const char* _name; + ConstraintType _validate_type; + +public: + // the "name" argument must be a string literal + CommandLineFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; + ~CommandLineFlagConstraint() {}; + const char* name() const { return _name; } + ConstraintType type() const { return _validate_type; } + virtual Flag::Error apply(bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; + virtual Flag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; +}; + +class CommandLineFlagConstraintList : public AllStatic { +private: + static GrowableArray* _constraints; + // Latest constraint validation type. + static CommandLineFlagConstraint::ConstraintType _validating_type; +public: + static void init(); + static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } + static CommandLineFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } + static CommandLineFlagConstraint* find(const char* name); + static CommandLineFlagConstraint* find_if_needs_check(const char* name); + static void add(CommandLineFlagConstraint* constraint) { _constraints->append(constraint); } + // True if 'AfterErgo' or later constraint functions are validated. + static bool validated_after_ergo() { return _validating_type >= CommandLineFlagConstraint::AfterErgo; }; + static bool check_constraints(CommandLineFlagConstraint::ConstraintType type); +}; + +#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP */ diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp similarity index 80% rename from src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp rename to src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp index 3055dfcd026..13d8498aa5e 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp @@ -29,22 +29,21 @@ #include "runtime/os.hpp" #include "interpreter/invocationCounter.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagConstraintsCompiler.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagConstraintsCompiler.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "utilities/defaultStream.hpp" -JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose) { +Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { if ((value <= 1) && (Arguments::mode() == Arguments::_comp || Arguments::mode() == Arguments::_mixed)) { CommandLineError::print(verbose, "AliasLevel (" INTX_FORMAT ") is not " "compatible with -Xcomp or -Xmixed\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -63,7 +62,7 @@ JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose) { * 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result, * the minimum number of compiler threads is 2. */ -JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { +Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; #if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI // case 1 @@ -86,37 +85,37 @@ JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { "CICompilerCount (" INTX_FORMAT ") must be " "at least %d \n", value, min_number_of_compiler_threads); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { +Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { if (value < 0 || value > 512) { CommandLineError::print(verbose, "AllocatePrefetchDistance (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", AllocatePrefetchDistance, 512); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { +Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { if (AllocatePrefetchStyle == 3) { if (value % wordSize != 0) { CommandLineError::print(verbose, "AllocatePrefetchStepSize (" INTX_FORMAT ") must be multiple of %d\n", value, wordSize); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { +Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { intx max_value = max_intx; #if defined(SPARC) max_value = 1; @@ -127,26 +126,26 @@ JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "AllocatePrefetchInstr (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", value, max_value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { +Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { if (value < 0 || value > INT_MAX >> InvocationCounter::count_shift) { CommandLineError::print(verbose, "CompileThreshold (" INTX_FORMAT ") " "must be between 0 and %d\n", value, INT_MAX >> InvocationCounter::count_shift); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { +Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { int backward_branch_limit; if (ProfileInterpreter) { if (OnStackReplacePercentage < InterpreterProfilePercentage) { @@ -154,7 +153,7 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) "OnStackReplacePercentage (" INTX_FORMAT ") must be " "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", OnStackReplacePercentage, InterpreterProfilePercentage); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } backward_branch_limit = ((CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100) @@ -168,14 +167,14 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) "CompileThreshold, InterpreterProfilePercentage, and/or OnStackReplacePercentage\n", (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100, INT_MAX >> InvocationCounter::count_shift); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } else { if (OnStackReplacePercentage < 0 ) { CommandLineError::print(verbose, "OnStackReplacePercentage (" INTX_FORMAT ") must be " "non-negative\n", OnStackReplacePercentage); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } backward_branch_limit = ((CompileThreshold * OnStackReplacePercentage) / 100) @@ -188,20 +187,20 @@ JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) "CompileThreshold and/or OnStackReplacePercentage\n", (CompileThreshold * OnStackReplacePercentage) / 100, INT_MAX >> InvocationCounter::count_shift); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { +Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) { CommandLineError::print(verbose, "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ") " "to align entry points\n", CodeCacheSegmentSize, CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (CodeCacheSegmentSize < sizeof(jdouble)) { @@ -209,7 +208,7 @@ JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " "at least " SIZE_FORMAT " to align constants\n", CodeCacheSegmentSize, sizeof(jdouble)); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #ifdef COMPILER2 @@ -219,14 +218,14 @@ JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ") " "to align inner loops\n", CodeCacheSegmentSize, OptoLoopAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { +Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { #ifdef SOLARIS if ((value < MinimumPriority || value > MaximumPriority) && (value != -1) && (value != -FXCriticalPriority)) { @@ -235,20 +234,20 @@ JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { "between %d and %d inclusively or -1 (means no change) " "or %d (special value for critical thread class/priority)\n", value, MinimumPriority, MaximumPriority, -FXCriticalPriority); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { +Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { #ifdef SPARC if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { CommandLineError::print(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "multiple of NOP size\n", CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif @@ -256,7 +255,7 @@ JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } if (CodeEntryAlignment < 16) { @@ -264,19 +263,19 @@ JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { "CodeEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", CodeEntryAlignment, 16); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { +Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "OptoLoopAlignment (" INTX_FORMAT ") " "must be a power of two\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } // Relevant on ppc, s390, sparc. Will be optimized where @@ -286,64 +285,64 @@ JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { "OptoLoopAlignment (" INTX_FORMAT ") must be " "multiple of NOP size (%d)\n", value, relocInfo::addr_unit()); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { +Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { if (value >= 4032) { CommandLineError::print(verbose, "ArraycopyDstPrefetchDistance (" UINTX_FORMAT ") must be" "between 0 and 4031\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { +Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { if (value >= 4032) { CommandLineError::print(verbose, "ArraycopySrcPrefetchDistance (" UINTX_FORMAT ") must be" "between 0 and 4031\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { +Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { for (int i = 0; i < 3; i++) { if (value % 10 > 2) { CommandLineError::print(verbose, "Invalid value (" UINTX_FORMAT ") " "in TypeProfileLevel at position %d\n", value, i); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } value = value / 10; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { +Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { if (value % BytesPerLong != 0) { - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } #ifdef COMPILER2 -JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { +Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { if (InteriorEntryAlignment > CodeEntryAlignment) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", InteriorEntryAlignment, CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #ifdef SPARC @@ -351,7 +350,7 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "multiple of NOP size\n"); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } #endif @@ -359,7 +358,7 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", InteriorEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } int minimum_alignment = 16; @@ -374,26 +373,26 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { "InteriorEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", InteriorEntryAlignment, minimum_alignment); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } -JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { +Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { if (value < MaxNodeLimit * 2 / 100 || value > MaxNodeLimit * 40 / 100) { CommandLineError::print(verbose, "NodeLimitFudgeFactor must be between 2%% and 40%% " "of MaxNodeLimit (" INTX_FORMAT ")\n", MaxNodeLimit); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } #endif // COMPILER2 -JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { +Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { #if INCLUDE_RTM_OPT if (UseRTMLocking && !is_power_of_2(RTMTotalCountIncrRate)) { CommandLineError::print(verbose, @@ -404,5 +403,5 @@ JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { } #endif - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp new file mode 100644 index 00000000000..b0596e93a19 --- /dev/null +++ b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP +#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP + +#include "runtime/globals.hpp" +#include "utilities/globalDefinitions.hpp" + +/* + * Here we have compiler arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +Flag::Error AliasLevelConstraintFunc(intx value, bool verbose); + +Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); + +Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose); + +Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); + +Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); + +Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); + +Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); + +Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose); + +#ifdef COMPILER2 +Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); +#endif + +Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose); + +#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp similarity index 77% rename from src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp rename to src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp index fdcb9bb193a..55483983094 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp @@ -24,21 +24,20 @@ #include "precompiled.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagConstraintsRuntime.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagConstraintsRuntime.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/task.hpp" #include "utilities/defaultStream.hpp" -JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { +Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } // In case page size is very small. if (value >= (intx)os::vm_page_size()) { @@ -46,99 +45,99 @@ JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "less than page size (" INTX_FORMAT ")\n", value, (intx)os::vm_page_size()); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } // Need to enforce the padding not to break the existing field alignments. // It is sufficient to check against the largest type size. -JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { +Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { if ((value % BytesPerLong) != 0) { CommandLineError::print(verbose, "ContendedPaddingWidth (" INTX_FORMAT ") must be " "a multiple of %d\n", value, BytesPerLong); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { +Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { if (value > BiasedLockingBulkRevokeThreshold) { CommandLineError::print(verbose, "BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ") must be " "less than or equal to BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRevokeThreshold); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { +Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran) != 0) { CommandLineError::print(verbose, "BiasedLockingStartupDelay (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", value, PeriodicTask::interval_gran); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { +Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { if (value < BiasedLockingBulkRebiasThreshold) { CommandLineError::print(verbose, "BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ") must be " "greater than or equal to BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRebiasThreshold); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else if ((double)value/(double)BiasedLockingDecayTime > 0.1) { CommandLineError::print(verbose, "The ratio of BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " "less than or equal to 0.1\n", value, BiasedLockingBulkRebiasThreshold); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { +Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { if (BiasedLockingBulkRebiasThreshold/(double)value > 0.1) { CommandLineError::print(verbose, "The ratio of BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " "less than or equal to 0.1\n", BiasedLockingBulkRebiasThreshold, value); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { +Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran != 0)) { CommandLineError::print(verbose, "PerfDataSamplingInterval (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", value, PeriodicTask::interval_gran); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } -JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { +Flag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { if (value) { if (!SafepointMechanism::supports_thread_local_poll()) { CommandLineError::print(verbose, "ThreadLocalHandshakes not yet supported on this platform\n"); - return JVMFlag::VIOLATES_CONSTRAINT; + return Flag::VIOLATES_CONSTRAINT; } } - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp similarity index 60% rename from src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp rename to src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp index 8763b83fd37..52452846df2 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp +++ b/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp @@ -22,10 +22,11 @@ * */ -#ifndef SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP -#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP +#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP +#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP -#include "runtime/flags/jvmFlag.hpp" +#include "runtime/globals.hpp" +#include "utilities/globalDefinitions.hpp" /* * Here we have runtime arguments constraints functions, which are called automatically @@ -33,18 +34,18 @@ * an appropriate error value. */ -JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); +Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); -JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); +Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); -JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); -JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); -JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); -JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); +Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); +Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); +Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); +Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); -JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); +Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); -JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose); +Flag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose); -#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP */ +#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */ diff --git a/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp b/src/hotspot/share/runtime/commandLineFlagRangeList.cpp similarity index 75% rename from src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp rename to src/hotspot/share/runtime/commandLineFlagRangeList.cpp index 97b074e59b9..a6973fc12cd 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp +++ b/src/hotspot/share/runtime/commandLineFlagRangeList.cpp @@ -29,9 +29,8 @@ #include "gc/shared/referenceProcessor.hpp" #include "oops/markOop.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" @@ -47,29 +46,29 @@ void CommandLineError::print(bool verbose, const char* msg, ...) { } } -class JVMFlagRange_int : public JVMFlagRange { +class CommandLineFlagRange_int : public CommandLineFlagRange { int _min; int _max; const int* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_int(const char* name, const int* ptr, int min, int max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_int(const char* name, const int* ptr, int min, int max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_int(*_ptr, verbose); } - JVMFlag::Error check_int(int value, bool verbose = true) { + Flag::Error check_int(int value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "int %s=%d is outside the allowed range " "[ %d ... %d ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -78,28 +77,28 @@ public: } }; -class JVMFlagRange_intx : public JVMFlagRange { +class CommandLineFlagRange_intx : public CommandLineFlagRange { intx _min; intx _max; const intx* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_intx(const char* name, const intx* ptr, intx min, intx max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_intx(const char* name, const intx* ptr, intx min, intx max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_intx(*_ptr, verbose); } - JVMFlag::Error check_intx(intx value, bool verbose = true) { + Flag::Error check_intx(intx value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "intx %s=" INTX_FORMAT " is outside the allowed range " "[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -108,29 +107,29 @@ public: } }; -class JVMFlagRange_uint : public JVMFlagRange { +class CommandLineFlagRange_uint : public CommandLineFlagRange { uint _min; uint _max; const uint* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_uint(const char* name, const uint* ptr, uint min, uint max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_uint(const char* name, const uint* ptr, uint min, uint max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_uint(*_ptr, verbose); } - JVMFlag::Error check_uint(uint value, bool verbose = true) { + Flag::Error check_uint(uint value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uint %s=%u is outside the allowed range " "[ %u ... %u ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -139,29 +138,29 @@ public: } }; -class JVMFlagRange_uintx : public JVMFlagRange { +class CommandLineFlagRange_uintx : public CommandLineFlagRange { uintx _min; uintx _max; const uintx* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_uintx(const char* name, const uintx* ptr, uintx min, uintx max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_uintx(const char* name, const uintx* ptr, uintx min, uintx max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_uintx(*_ptr, verbose); } - JVMFlag::Error check_uintx(uintx value, bool verbose = true) { + Flag::Error check_uintx(uintx value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uintx %s=" UINTX_FORMAT " is outside the allowed range " "[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -170,29 +169,29 @@ public: } }; -class JVMFlagRange_uint64_t : public JVMFlagRange { +class CommandLineFlagRange_uint64_t : public CommandLineFlagRange { uint64_t _min; uint64_t _max; const uint64_t* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_uint64_t(*_ptr, verbose); } - JVMFlag::Error check_uint64_t(uint64_t value, bool verbose = true) { + Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uint64_t %s=" UINT64_FORMAT " is outside the allowed range " "[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -201,29 +200,29 @@ public: } }; -class JVMFlagRange_size_t : public JVMFlagRange { +class CommandLineFlagRange_size_t : public CommandLineFlagRange { size_t _min; size_t _max; const size_t* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_size_t(const char* name, const size_t* ptr, size_t min, size_t max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_size_t(const char* name, const size_t* ptr, size_t min, size_t max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_size_t(*_ptr, verbose); } - JVMFlag::Error check_size_t(size_t value, bool verbose = true) { + Flag::Error check_size_t(size_t value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "size_t %s=" SIZE_FORMAT " is outside the allowed range " "[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -232,29 +231,29 @@ public: } }; -class JVMFlagRange_double : public JVMFlagRange { +class CommandLineFlagRange_double : public CommandLineFlagRange { double _min; double _max; const double* _ptr; public: // the "name" argument must be a string literal - JVMFlagRange_double(const char* name, const double* ptr, double min, double max) - : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + CommandLineFlagRange_double(const char* name, const double* ptr, double min, double max) + : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - JVMFlag::Error check(bool verbose = true) { + Flag::Error check(bool verbose = true) { return check_double(*_ptr, verbose); } - JVMFlag::Error check_double(double value, bool verbose = true) { + Flag::Error check_double(double value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "double %s=%f is outside the allowed range " "[ %f ... %f ]\n", name(), value, _min, _max); - return JVMFlag::OUT_OF_BOUNDS; + return Flag::OUT_OF_BOUNDS; } else { - return JVMFlag::SUCCESS; + return Flag::SUCCESS; } } @@ -278,27 +277,27 @@ void emit_range_uint64_t(const char* /*name*/, const uint64_t* /*value*/) { / void emit_range_size_t(const char* /*name*/, const size_t* /*value*/) { /* NOP */ } void emit_range_double(const char* /*name*/, const double* /*value*/) { /* NOP */ } -// JVMFlagRange emitting code functions if range arguments are provided +// CommandLineFlagRange emitting code functions if range arguments are provided void emit_range_int(const char* name, const int* ptr, int min, int max) { - JVMFlagRangeList::add(new JVMFlagRange_int(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_int(name, ptr, min, max)); } void emit_range_intx(const char* name, const intx* ptr, intx min, intx max) { - JVMFlagRangeList::add(new JVMFlagRange_intx(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_intx(name, ptr, min, max)); } void emit_range_uint(const char* name, const uint* ptr, uint min, uint max) { - JVMFlagRangeList::add(new JVMFlagRange_uint(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_uint(name, ptr, min, max)); } void emit_range_uintx(const char* name, const uintx* ptr, uintx min, uintx max) { - JVMFlagRangeList::add(new JVMFlagRange_uintx(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_uintx(name, ptr, min, max)); } void emit_range_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) { - JVMFlagRangeList::add(new JVMFlagRange_uint64_t(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_uint64_t(name, ptr, min, max)); } void emit_range_size_t(const char* name, const size_t* ptr, size_t min, size_t max) { - JVMFlagRangeList::add(new JVMFlagRange_size_t(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_size_t(name, ptr, min, max)); } void emit_range_double(const char* name, const double* ptr, double min, double max) { - JVMFlagRangeList::add(new JVMFlagRange_double(name, ptr, min, max)); + CommandLineFlagRangeList::add(new CommandLineFlagRange_double(name, ptr, min, max)); } // Generate code to call emit_range_xxx function @@ -329,12 +328,12 @@ void emit_range_double(const char* name, const double* ptr, double min, double m #define EMIT_RANGE_CHECK(a, b) , a, b #define INITIAL_RANGES_SIZE 379 -GrowableArray* JVMFlagRangeList::_ranges = NULL; +GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them -void JVMFlagRangeList::init(void) { +void CommandLineFlagRangeList::init(void) { - _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_RANGES_SIZE, true); + _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_RANGES_SIZE, true); emit_range_no(NULL VM_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, EMIT_RANGE_PD_DEVELOPER_FLAG, @@ -404,10 +403,10 @@ void JVMFlagRangeList::init(void) { #endif // COMPILER2 } -JVMFlagRange* JVMFlagRangeList::find(const char* name) { - JVMFlagRange* found = NULL; +CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) { + CommandLineFlagRange* found = NULL; for (int i=0; iname(), name) == 0) { found = range; break; @@ -416,12 +415,12 @@ JVMFlagRange* JVMFlagRangeList::find(const char* name) { return found; } -void JVMFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { - JVMFlagRange* range = JVMFlagRangeList::find(name); +void CommandLineFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); if (range != NULL) { range->print(st); } else { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find(name); + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); if (constraint != NULL) { assert(default_range_str_func!=NULL, "default_range_str_func must be provided"); st->print("%s", default_range_str_func()); @@ -431,12 +430,12 @@ void JVMFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc de } } -bool JVMFlagRangeList::check_ranges() { +bool CommandLineFlagRangeList::check_ranges() { // Check ranges. bool status = true; for (int i=0; icheck(true) != JVMFlag::SUCCESS) status = false; + CommandLineFlagRange* range = at(i); + if (range->check(true) != Flag::SUCCESS) status = false; } return status; } diff --git a/src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp b/src/hotspot/share/runtime/commandLineFlagRangeList.hpp similarity index 56% rename from src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp rename to src/hotspot/share/runtime/commandLineFlagRangeList.hpp index 6fa23cea244..318973505a5 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp +++ b/src/hotspot/share/runtime/commandLineFlagRangeList.hpp @@ -22,11 +22,11 @@ * */ -#ifndef SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP -#define SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP +#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP +#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP #include "memory/metaspaceShared.hpp" -#include "runtime/flags/jvmFlag.hpp" +#include "runtime/globals.hpp" #include "utilities/growableArray.hpp" /* @@ -44,36 +44,36 @@ public: static void print(bool verbose, const char* msg, ...); }; -class JVMFlagRange : public CHeapObj { +class CommandLineFlagRange : public CHeapObj { private: const char* _name; public: // the "name" argument must be a string literal - JVMFlagRange(const char* name) { _name=name; } - ~JVMFlagRange() {} + CommandLineFlagRange(const char* name) { _name=name; } + ~CommandLineFlagRange() {} const char* name() { return _name; } - virtual JVMFlag::Error check(bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } - virtual JVMFlag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual Flag::Error check(bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual Flag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } virtual void print(outputStream* st) { ; } }; -class JVMFlagRangeList : public AllStatic { - static GrowableArray* _ranges; +class CommandLineFlagRangeList : public AllStatic { + static GrowableArray* _ranges; public: static void init(); static int length() { return (_ranges != NULL) ? _ranges->length() : 0; } - static JVMFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } - static JVMFlagRange* find(const char* name); - static void add(JVMFlagRange* range) { _ranges->append(range); } + static CommandLineFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } + static CommandLineFlagRange* find(const char* name); + static void add(CommandLineFlagRange* range) { _ranges->append(range); } static void print(outputStream* st, const char* name, RangeStrFunc default_range_str_func); // Check the final values of all flags for ranges. static bool check_ranges(); }; -#endif // SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP +#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP diff --git a/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp b/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp similarity index 76% rename from src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp rename to src/hotspot/share/runtime/commandLineFlagWriteableList.cpp index a80d21c0d34..214e614afc8 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp +++ b/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/plab.hpp" -#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/commandLineFlagWriteableList.hpp" #include "runtime/os.hpp" #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -36,18 +36,18 @@ #include "jvmci/jvmci_globals.hpp" #endif -bool JVMFlagWriteable::is_writeable(void) { +bool CommandLineFlagWriteable::is_writeable(void) { return _writeable; } -void JVMFlagWriteable::mark_once(void) { +void CommandLineFlagWriteable::mark_once(void) { if (_type == Once) { _writeable = false; } } -void JVMFlagWriteable::mark_startup(void) { - if (_type == JVMFlagWriteable::CommandLineOnly) { +void CommandLineFlagWriteable::mark_startup(void) { + if (_type == CommandLineFlagWriteable::CommandLineOnly) { _writeable = false; } } @@ -67,30 +67,30 @@ void emit_writeable_uint64_t(const char* /*name*/) { /* NOP */ } void emit_writeable_size_t(const char* /*name*/) { /* NOP */ } void emit_writeable_double(const char* /*name*/) { /* NOP */ } -// JVMFlagWriteable emitting code functions if range arguments are provided -void emit_writeable_bool(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +// CommandLineFlagWriteable emitting code functions if range arguments are provided +void emit_writeable_bool(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_int(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_int(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_intx(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_intx(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_uint(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_uint(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_uintx(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_uintx(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_uint64_t(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_uint64_t(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_size_t(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_size_t(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } -void emit_writeable_double(const char* name, JVMFlagWriteable::WriteableType type) { - JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); +void emit_writeable_double(const char* name, CommandLineFlagWriteable::WriteableType type) { + CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); } // Generate code to call emit_writeable_xxx function @@ -108,14 +108,14 @@ void emit_writeable_double(const char* name, JVMFlagWriteable::WriteableType typ #define EMIT_WRITEABLE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_writeable_##type(#name // Generate type argument to pass into emit_writeable_xxx functions -#define EMIT_WRITEABLE(a) , JVMFlagWriteable::a +#define EMIT_WRITEABLE(a) , CommandLineFlagWriteable::a #define INITIAL_WRITEABLES_SIZE 2 -GrowableArray* JVMFlagWriteableList::_controls = NULL; +GrowableArray* CommandLineFlagWriteableList::_controls = NULL; -void JVMFlagWriteableList::init(void) { +void CommandLineFlagWriteableList::init(void) { - _controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_WRITEABLES_SIZE, true); + _controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_WRITEABLES_SIZE, true); emit_writeable_no(NULL VM_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG, EMIT_WRITEABLE_PD_DEVELOPER_FLAG, @@ -185,10 +185,10 @@ void JVMFlagWriteableList::init(void) { #endif // COMPILER2 } -JVMFlagWriteable* JVMFlagWriteableList::find(const char* name) { - JVMFlagWriteable* found = NULL; +CommandLineFlagWriteable* CommandLineFlagWriteableList::find(const char* name) { + CommandLineFlagWriteable* found = NULL; for (int i=0; iname(), name) == 0) { found = writeable; break; @@ -197,9 +197,9 @@ JVMFlagWriteable* JVMFlagWriteableList::find(const char* name) { return found; } -void JVMFlagWriteableList::mark_startup(void) { +void CommandLineFlagWriteableList::mark_startup(void) { for (int i=0; imark_startup(); } } diff --git a/src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp b/src/hotspot/share/runtime/commandLineFlagWriteableList.hpp similarity index 70% rename from src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp rename to src/hotspot/share/runtime/commandLineFlagWriteableList.hpp index aca87e30f1f..84220851fb2 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp +++ b/src/hotspot/share/runtime/commandLineFlagWriteableList.hpp @@ -22,12 +22,13 @@ * */ -#ifndef SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP -#define SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP +#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP +#define SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP +#include "runtime/globals.hpp" #include "utilities/growableArray.hpp" -class JVMFlagWriteable : public CHeapObj { +class CommandLineFlagWriteable : public CHeapObj { public: enum WriteableType { // can be set without any limits @@ -44,8 +45,8 @@ private: bool _startup_done; public: // the "name" argument must be a string literal - JVMFlagWriteable(const char* name, WriteableType type) { _name=name; _type=type; _writeable=true; _startup_done=false; } - ~JVMFlagWriteable() {} + CommandLineFlagWriteable(const char* name, WriteableType type) { _name=name; _type=type; _writeable=true; _startup_done=false; } + ~CommandLineFlagWriteable() {} const char* name() { return _name; } const WriteableType type() { return _type; } bool is_writeable(void); @@ -53,15 +54,15 @@ public: void mark_startup(void); }; -class JVMFlagWriteableList : public AllStatic { - static GrowableArray* _controls; +class CommandLineFlagWriteableList : public AllStatic { + static GrowableArray* _controls; public: static void init(); static int length() { return (_controls != NULL) ? _controls->length() : 0; } - static JVMFlagWriteable* at(int i) { return (_controls != NULL) ? _controls->at(i) : NULL; } - static JVMFlagWriteable* find(const char* name); - static void add(JVMFlagWriteable* range) { _controls->append(range); } + static CommandLineFlagWriteable* at(int i) { return (_controls != NULL) ? _controls->at(i) : NULL; } + static CommandLineFlagWriteable* find(const char* name); + static void add(CommandLineFlagWriteable* range) { _controls->append(range); } static void mark_startup(void); }; -#endif // SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP +#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP diff --git a/src/hotspot/share/runtime/flags/flagSetting.hpp b/src/hotspot/share/runtime/flags/flagSetting.hpp deleted file mode 100644 index f2f629b0fb3..00000000000 --- a/src/hotspot/share/runtime/flags/flagSetting.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP -#define SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP - -#include "memory/allocation.hpp" - -// debug flags control various aspects of the VM and are global accessible - -// use FlagSetting to temporarily change some debug flag -// e.g. FlagSetting fs(DebugThisAndThat, true); -// restored to previous value upon leaving scope -class FlagSetting : public StackObj { - bool val; - bool* flag; -public: - FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; } - ~FlagSetting() { *flag = val; } -}; - -class UIntFlagSetting : public StackObj { - uint val; - uint* flag; -public: - UIntFlagSetting(uint& fl, uint newValue) { flag = &fl; val = fl; fl = newValue; } - ~UIntFlagSetting() { *flag = val; } -}; - -class SizeTFlagSetting : public StackObj { - size_t val; - size_t* flag; -public: - SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } - ~SizeTFlagSetting() { *flag = val; } -}; - -// Helper class for temporarily saving the value of a flag during a scope. -template -class FlagGuard { - unsigned char _value[SIZE]; - void* const _addr; -public: - FlagGuard(void* flag_addr) : _addr(flag_addr) { memcpy(_value, _addr, SIZE); } - ~FlagGuard() { memcpy(_addr, _value, SIZE); } -}; - -#define FLAG_GUARD(f) FlagGuard f ## _guard(&f) - -#endif // SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp deleted file mode 100644 index b6f6b55f2ea..00000000000 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ /dev/null @@ -1,1506 +0,0 @@ -/* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" -#include "runtime/flags/jvmFlagWriteableList.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" -#include "runtime/globals_extension.hpp" -#include "trace/tracing.hpp" -#include "utilities/defaultStream.hpp" -#include "utilities/stringUtils.hpp" - -#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 -static char* create_range_str(const char *fmt, ...) { - static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; - static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); - - int size_needed = 0; - do { - va_list args; - va_start(args, fmt); - size_needed = jio_vsnprintf(range_string, string_length, fmt, args); - va_end(args); - - if (size_needed < 0) { - string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; - range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); - guarantee(range_string != NULL, "create_range_str string should not be NULL"); - } - } while (size_needed < 0); - - return range_string; -} - -const char* JVMFlag::get_int_default_range_str() { - return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); -} - -const char* JVMFlag::get_uint_default_range_str() { - return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); -} - -const char* JVMFlag::get_intx_default_range_str() { - return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); -} - -const char* JVMFlag::get_uintx_default_range_str() { - return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); -} - -const char* JVMFlag::get_uint64_t_default_range_str() { - return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); -} - -const char* JVMFlag::get_size_t_default_range_str() { - return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); -} - -const char* JVMFlag::get_double_default_range_str() { - return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); -} - -static bool is_product_build() { -#ifdef PRODUCT - return true; -#else - return false; -#endif -} - -JVMFlag::Error JVMFlag::check_writable(bool changed) { - if (is_constant_in_binary()) { - fatal("flag is constant: %s", _name); - } - - JVMFlag::Error error = JVMFlag::SUCCESS; - if (changed) { - JVMFlagWriteable* writeable = JVMFlagWriteableList::find(_name); - if (writeable) { - if (writeable->is_writeable() == false) { - switch (writeable->type()) - { - case JVMFlagWriteable::Once: - error = JVMFlag::SET_ONLY_ONCE; - jio_fprintf(defaultStream::error_stream(), "Error: %s may not be set more than once\n", _name); - break; - case JVMFlagWriteable::CommandLineOnly: - error = JVMFlag::COMMAND_LINE_ONLY; - jio_fprintf(defaultStream::error_stream(), "Error: %s may be modified only from commad line\n", _name); - break; - default: - ShouldNotReachHere(); - break; - } - } - writeable->mark_once(); - } - } - return error; -} - -bool JVMFlag::is_bool() const { - return strcmp(_type, "bool") == 0; -} - -bool JVMFlag::get_bool() const { - return *((bool*) _addr); -} - -JVMFlag::Error JVMFlag::set_bool(bool value) { - JVMFlag::Error error = check_writable(value!=get_bool()); - if (error == JVMFlag::SUCCESS) { - *((bool*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_int() const { - return strcmp(_type, "int") == 0; -} - -int JVMFlag::get_int() const { - return *((int*) _addr); -} - -JVMFlag::Error JVMFlag::set_int(int value) { - JVMFlag::Error error = check_writable(value!=get_int()); - if (error == JVMFlag::SUCCESS) { - *((int*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_uint() const { - return strcmp(_type, "uint") == 0; -} - -uint JVMFlag::get_uint() const { - return *((uint*) _addr); -} - -JVMFlag::Error JVMFlag::set_uint(uint value) { - JVMFlag::Error error = check_writable(value!=get_uint()); - if (error == JVMFlag::SUCCESS) { - *((uint*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_intx() const { - return strcmp(_type, "intx") == 0; -} - -intx JVMFlag::get_intx() const { - return *((intx*) _addr); -} - -JVMFlag::Error JVMFlag::set_intx(intx value) { - JVMFlag::Error error = check_writable(value!=get_intx()); - if (error == JVMFlag::SUCCESS) { - *((intx*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_uintx() const { - return strcmp(_type, "uintx") == 0; -} - -uintx JVMFlag::get_uintx() const { - return *((uintx*) _addr); -} - -JVMFlag::Error JVMFlag::set_uintx(uintx value) { - JVMFlag::Error error = check_writable(value!=get_uintx()); - if (error == JVMFlag::SUCCESS) { - *((uintx*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_uint64_t() const { - return strcmp(_type, "uint64_t") == 0; -} - -uint64_t JVMFlag::get_uint64_t() const { - return *((uint64_t*) _addr); -} - -JVMFlag::Error JVMFlag::set_uint64_t(uint64_t value) { - JVMFlag::Error error = check_writable(value!=get_uint64_t()); - if (error == JVMFlag::SUCCESS) { - *((uint64_t*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_size_t() const { - return strcmp(_type, "size_t") == 0; -} - -size_t JVMFlag::get_size_t() const { - return *((size_t*) _addr); -} - -JVMFlag::Error JVMFlag::set_size_t(size_t value) { - JVMFlag::Error error = check_writable(value!=get_size_t()); - if (error == JVMFlag::SUCCESS) { - *((size_t*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_double() const { - return strcmp(_type, "double") == 0; -} - -double JVMFlag::get_double() const { - return *((double*) _addr); -} - -JVMFlag::Error JVMFlag::set_double(double value) { - JVMFlag::Error error = check_writable(value!=get_double()); - if (error == JVMFlag::SUCCESS) { - *((double*) _addr) = value; - } - return error; -} - -bool JVMFlag::is_ccstr() const { - return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; -} - -bool JVMFlag::ccstr_accumulates() const { - return strcmp(_type, "ccstrlist") == 0; -} - -ccstr JVMFlag::get_ccstr() const { - return *((ccstr*) _addr); -} - -JVMFlag::Error JVMFlag::set_ccstr(ccstr value) { - JVMFlag::Error error = check_writable(value!=get_ccstr()); - if (error == JVMFlag::SUCCESS) { - *((ccstr*) _addr) = value; - } - return error; -} - - -JVMFlag::Flags JVMFlag::get_origin() { - return Flags(_flags & VALUE_ORIGIN_MASK); -} - -void JVMFlag::set_origin(Flags origin) { - assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); - Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); - _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); -} - -bool JVMFlag::is_default() { - return (get_origin() == DEFAULT); -} - -bool JVMFlag::is_ergonomic() { - return (get_origin() == ERGONOMIC); -} - -bool JVMFlag::is_command_line() { - return (_flags & ORIG_COMMAND_LINE) != 0; -} - -void JVMFlag::set_command_line() { - _flags = Flags(_flags | ORIG_COMMAND_LINE); -} - -bool JVMFlag::is_product() const { - return (_flags & KIND_PRODUCT) != 0; -} - -bool JVMFlag::is_manageable() const { - return (_flags & KIND_MANAGEABLE) != 0; -} - -bool JVMFlag::is_diagnostic() const { - return (_flags & KIND_DIAGNOSTIC) != 0; -} - -bool JVMFlag::is_experimental() const { - return (_flags & KIND_EXPERIMENTAL) != 0; -} - -bool JVMFlag::is_notproduct() const { - return (_flags & KIND_NOT_PRODUCT) != 0; -} - -bool JVMFlag::is_develop() const { - return (_flags & KIND_DEVELOP) != 0; -} - -bool JVMFlag::is_read_write() const { - return (_flags & KIND_READ_WRITE) != 0; -} - -bool JVMFlag::is_commercial() const { - return (_flags & KIND_COMMERCIAL) != 0; -} - -/** - * Returns if this flag is a constant in the binary. Right now this is - * true for notproduct and develop flags in product builds. - */ -bool JVMFlag::is_constant_in_binary() const { -#ifdef PRODUCT - return is_notproduct() || is_develop(); -#else - return false; -#endif -} - -bool JVMFlag::is_unlocker() const { - return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || - strcmp(_name, "UnlockExperimentalVMOptions") == 0 || - is_unlocker_ext(); -} - -bool JVMFlag::is_unlocked() const { - if (is_diagnostic()) { - return UnlockDiagnosticVMOptions; - } - if (is_experimental()) { - return UnlockExperimentalVMOptions; - } - return is_unlocked_ext(); -} - -void JVMFlag::clear_diagnostic() { - assert(is_diagnostic(), "sanity"); - _flags = Flags(_flags & ~KIND_DIAGNOSTIC); - assert(!is_diagnostic(), "sanity"); -} - -// Get custom message for this locked flag, or NULL if -// none is available. Returns message type produced. -JVMFlag::MsgType JVMFlag::get_locked_message(char* buf, int buflen) const { - buf[0] = '\0'; - if (is_diagnostic() && !is_unlocked()) { - jio_snprintf(buf, buflen, - "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" - "Error: The unlock option must precede '%s'.\n", - _name, _name); - return JVMFlag::DIAGNOSTIC_FLAG_BUT_LOCKED; - } - if (is_experimental() && !is_unlocked()) { - jio_snprintf(buf, buflen, - "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" - "Error: The unlock option must precede '%s'.\n", - _name, _name); - return JVMFlag::EXPERIMENTAL_FLAG_BUT_LOCKED; - } - if (is_develop() && is_product_build()) { - jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", - _name); - return JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; - } - if (is_notproduct() && is_product_build()) { - jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", - _name); - return JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; - } - return get_locked_message_ext(buf, buflen); -} - -bool JVMFlag::is_writeable() const { - return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); -} - -// All flags except "manageable" are assumed to be internal flags. -// Long term, we need to define a mechanism to specify which flags -// are external/stable and change this function accordingly. -bool JVMFlag::is_external() const { - return is_manageable() || is_external_ext(); -} - -// Helper function for JVMFlag::print_on(). -// Fills current line up to requested position. -// Should the current position already be past the requested position, -// one separator blank is enforced. -void fill_to_pos(outputStream* st, unsigned int req_pos) { - if ((unsigned int)st->position() < req_pos) { - st->fill_to(req_pos); // need to fill with blanks to reach req_pos - } else { - st->print(" "); // enforce blank separation. Previous field too long. - } -} - -void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) { - // Don't print notproduct and develop flags in a product build. - if (is_constant_in_binary()) { - return; - } - - if (!printRanges) { - // The command line options -XX:+PrintFlags* cause this function to be called - // for each existing flag to print information pertinent to this flag. The data - // is displayed in columnar form, with the following layout: - // col1 - data type, right-justified - // col2 - name, left-justified - // col3 - ' =' double-char, leading space to align with possible '+=' - // col4 - value left-justified - // col5 - kind right-justified - // col6 - origin left-justified - // col7 - comments left-justified - // - // The column widths are fixed. They are defined such that, for most cases, - // an eye-pleasing tabular output is created. - // - // Sample output: - // bool CMSScavengeBeforeRemark = false {product} {default} - // uintx CMSScheduleRemarkEdenPenetration = 50 {product} {default} - // size_t CMSScheduleRemarkEdenSizeThreshold = 2097152 {product} {default} - // uintx CMSScheduleRemarkSamplingRatio = 5 {product} {default} - // double CMSSmallCoalSurplusPercent = 1.050000 {product} {default} - // ccstr CompileCommandFile = MyFile.cmd {product} {command line} - // ccstrlist CompileOnly = Method1 - // CompileOnly += Method2 {product} {command line} - // | | | | | | | - // | | | | | | +-- col7 - // | | | | | +-- col6 - // | | | | +-- col5 - // | | | +-- col4 - // | | +-- col3 - // | +-- col2 - // +-- col1 - - const unsigned int col_spacing = 1; - const unsigned int col1_pos = 0; - const unsigned int col1_width = 9; - const unsigned int col2_pos = col1_pos + col1_width + col_spacing; - const unsigned int col2_width = 39; - const unsigned int col3_pos = col2_pos + col2_width + col_spacing; - const unsigned int col3_width = 2; - const unsigned int col4_pos = col3_pos + col3_width + col_spacing; - const unsigned int col4_width = 30; - const unsigned int col5_pos = col4_pos + col4_width + col_spacing; - const unsigned int col5_width = 20; - const unsigned int col6_pos = col5_pos + col5_width + col_spacing; - const unsigned int col6_width = 15; - const unsigned int col7_pos = col6_pos + col6_width + col_spacing; - const unsigned int col7_width = 1; - - st->fill_to(col1_pos); - st->print("%*s", col1_width, _type); // right-justified, therefore width is required. - - fill_to_pos(st, col2_pos); - st->print("%s", _name); - - fill_to_pos(st, col3_pos); - st->print(" ="); // use " =" for proper alignment with multiline ccstr output. - - fill_to_pos(st, col4_pos); - if (is_bool()) { - st->print("%s", get_bool() ? "true" : "false"); - } else if (is_int()) { - st->print("%d", get_int()); - } else if (is_uint()) { - st->print("%u", get_uint()); - } else if (is_intx()) { - st->print(INTX_FORMAT, get_intx()); - } else if (is_uintx()) { - st->print(UINTX_FORMAT, get_uintx()); - } else if (is_uint64_t()) { - st->print(UINT64_FORMAT, get_uint64_t()); - } else if (is_size_t()) { - st->print(SIZE_FORMAT, get_size_t()); - } else if (is_double()) { - st->print("%f", get_double()); - } else if (is_ccstr()) { - // Honor characters in ccstr: print multiple lines. - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - size_t llen = pointer_delta(eol, cp, sizeof(char)); - st->print("%.*s", (int)llen, cp); - st->cr(); - cp = eol+1; - fill_to_pos(st, col2_pos); - st->print("%s", _name); - fill_to_pos(st, col3_pos); - st->print("+="); - fill_to_pos(st, col4_pos); - } - st->print("%s", cp); - } - } else { - st->print("unhandled type %s", _type); - st->cr(); - return; - } - - fill_to_pos(st, col5_pos); - print_kind(st, col5_width); - - fill_to_pos(st, col6_pos); - print_origin(st, col6_width); - -#ifndef PRODUCT - if (withComments) { - fill_to_pos(st, col7_pos); - st->print("%s", _doc); - } -#endif - st->cr(); - } else if (!is_bool() && !is_ccstr()) { - // The command line options -XX:+PrintFlags* cause this function to be called - // for each existing flag to print information pertinent to this flag. The data - // is displayed in columnar form, with the following layout: - // col1 - data type, right-justified - // col2 - name, left-justified - // col4 - range [ min ... max] - // col5 - kind right-justified - // col6 - origin left-justified - // col7 - comments left-justified - // - // The column widths are fixed. They are defined such that, for most cases, - // an eye-pleasing tabular output is created. - // - // Sample output: - // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} - // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} - // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} - // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} - // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} - // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} - // | | | | | | - // | | | | | +-- col7 - // | | | | +-- col6 - // | | | +-- col5 - // | | +-- col4 - // | +-- col2 - // +-- col1 - - const unsigned int col_spacing = 1; - const unsigned int col1_pos = 0; - const unsigned int col1_width = 9; - const unsigned int col2_pos = col1_pos + col1_width + col_spacing; - const unsigned int col2_width = 49; - const unsigned int col3_pos = col2_pos + col2_width + col_spacing; - const unsigned int col3_width = 0; - const unsigned int col4_pos = col3_pos + col3_width + col_spacing; - const unsigned int col4_width = 60; - const unsigned int col5_pos = col4_pos + col4_width + col_spacing; - const unsigned int col5_width = 35; - const unsigned int col6_pos = col5_pos + col5_width + col_spacing; - const unsigned int col6_width = 15; - const unsigned int col7_pos = col6_pos + col6_width + col_spacing; - const unsigned int col7_width = 1; - - st->fill_to(col1_pos); - st->print("%*s", col1_width, _type); // right-justified, therefore width is required. - - fill_to_pos(st, col2_pos); - st->print("%s", _name); - - fill_to_pos(st, col4_pos); - RangeStrFunc func = NULL; - if (is_int()) { - func = JVMFlag::get_int_default_range_str; - } else if (is_uint()) { - func = JVMFlag::get_uint_default_range_str; - } else if (is_intx()) { - func = JVMFlag::get_intx_default_range_str; - } else if (is_uintx()) { - func = JVMFlag::get_uintx_default_range_str; - } else if (is_uint64_t()) { - func = JVMFlag::get_uint64_t_default_range_str; - } else if (is_size_t()) { - func = JVMFlag::get_size_t_default_range_str; - } else if (is_double()) { - func = JVMFlag::get_double_default_range_str; - } else { - st->print("unhandled type %s", _type); - st->cr(); - return; - } - JVMFlagRangeList::print(st, _name, func); - - fill_to_pos(st, col5_pos); - print_kind(st, col5_width); - - fill_to_pos(st, col6_pos); - print_origin(st, col6_width); - -#ifndef PRODUCT - if (withComments) { - fill_to_pos(st, col7_pos); - st->print("%s", _doc); - } -#endif - st->cr(); - } -} - -void JVMFlag::print_kind(outputStream* st, unsigned int width) { - struct Data { - int flag; - const char* name; - }; - - Data data[] = { - { KIND_JVMCI, "JVMCI" }, - { KIND_C1, "C1" }, - { KIND_C2, "C2" }, - { KIND_ARCH, "ARCH" }, - { KIND_PLATFORM_DEPENDENT, "pd" }, - { KIND_PRODUCT, "product" }, - { KIND_MANAGEABLE, "manageable" }, - { KIND_DIAGNOSTIC, "diagnostic" }, - { KIND_EXPERIMENTAL, "experimental" }, - { KIND_COMMERCIAL, "commercial" }, - { KIND_NOT_PRODUCT, "notproduct" }, - { KIND_DEVELOP, "develop" }, - { KIND_LP64_PRODUCT, "lp64_product" }, - { KIND_READ_WRITE, "rw" }, - { -1, "" } - }; - - if ((_flags & KIND_MASK) != 0) { - bool is_first = true; - const size_t buffer_size = 64; - size_t buffer_used = 0; - char kind[buffer_size]; - - jio_snprintf(kind, buffer_size, "{"); - buffer_used++; - for (int i = 0; data[i].flag != -1; i++) { - Data d = data[i]; - if ((_flags & d.flag) != 0) { - if (is_first) { - is_first = false; - } else { - assert(buffer_used + 1 < buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); - buffer_used++; - } - size_t length = strlen(d.name); - assert(buffer_used + length < buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); - buffer_used += length; - } - } - assert(buffer_used + 2 <= buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); - st->print("%*s", width, kind); - } -} - -void JVMFlag::print_origin(outputStream* st, unsigned int width) { - int origin = _flags & VALUE_ORIGIN_MASK; - st->print("{"); - switch(origin) { - case DEFAULT: - st->print("default"); break; - case COMMAND_LINE: - st->print("command line"); break; - case ENVIRON_VAR: - st->print("environment"); break; - case CONFIG_FILE: - st->print("config file"); break; - case MANAGEMENT: - st->print("management"); break; - case ERGONOMIC: - if (_flags & ORIG_COMMAND_LINE) { - st->print("command line, "); - } - st->print("ergonomic"); break; - case ATTACH_ON_DEMAND: - st->print("attach"); break; - case INTERNAL: - st->print("internal"); break; - } - st->print("}"); -} - -void JVMFlag::print_as_flag(outputStream* st) { - if (is_bool()) { - st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); - } else if (is_int()) { - st->print("-XX:%s=%d", _name, get_int()); - } else if (is_uint()) { - st->print("-XX:%s=%u", _name, get_uint()); - } else if (is_intx()) { - st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); - } else if (is_uintx()) { - st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); - } else if (is_uint64_t()) { - st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); - } else if (is_size_t()) { - st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); - } else if (is_double()) { - st->print("-XX:%s=%f", _name, get_double()); - } else if (is_ccstr()) { - st->print("-XX:%s=", _name); - const char* cp = get_ccstr(); - if (cp != NULL) { - // Need to turn embedded '\n's back into separate arguments - // Not so efficient to print one character at a time, - // but the choice is to do the transformation to a buffer - // and print that. And this need not be efficient. - for (; *cp != '\0'; cp += 1) { - switch (*cp) { - default: - st->print("%c", *cp); - break; - case '\n': - st->print(" -XX:%s=", _name); - break; - } - } - } - } else { - ShouldNotReachHere(); - } -} - -const char* JVMFlag::flag_error_str(JVMFlag::Error error) { - switch (error) { - case JVMFlag::MISSING_NAME: return "MISSING_NAME"; - case JVMFlag::MISSING_VALUE: return "MISSING_VALUE"; - case JVMFlag::NON_WRITABLE: return "NON_WRITABLE"; - case JVMFlag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; - case JVMFlag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; - case JVMFlag::INVALID_FLAG: return "INVALID_FLAG"; - case JVMFlag::ERR_OTHER: return "ERR_OTHER"; - case JVMFlag::SUCCESS: return "SUCCESS"; - default: ShouldNotReachHere(); return "NULL"; - } -} - -// 4991491 do not "optimize out" the was_set false values: omitting them -// tickles a Microsoft compiler bug causing flagTable to be malformed - -#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT) }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DIAGNOSTIC) }, -#define RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_EXPERIMENTAL) }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_MANAGEABLE) }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_READ_WRITE) }, -#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DEVELOP) }, -#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_NOT_PRODUCT) }, - -#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_PRODUCT) }, -#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DIAGNOSTIC) }, -#define JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_EXPERIMENTAL) }, -#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DEVELOP) }, -#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_NOT_PRODUCT) }, - -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_LP64_PRODUCT) }, -#else -#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ -#endif // _LP64 - -#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_PRODUCT) }, -#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DIAGNOSTIC) }, -#define C1_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DEVELOP) }, -#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_NOT_PRODUCT) }, - -#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_PRODUCT) }, -#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DIAGNOSTIC) }, -#define C2_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_EXPERIMENTAL) }, -#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DEVELOP) }, -#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, -#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_NOT_PRODUCT) }, - -#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_PRODUCT) }, -#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_DIAGNOSTIC) }, -#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_EXPERIMENTAL) }, -#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_DEVELOP) }, -#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_NOT_PRODUCT) }, - -static JVMFlag flagTable[] = { - VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PRODUCT_FLAG_STRUCT, \ - RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ - RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \ - RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ - RUNTIME_MANAGEABLE_FLAG_STRUCT, \ - RUNTIME_PRODUCT_RW_FLAG_STRUCT, \ - RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) - - RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PRODUCT_FLAG_STRUCT, \ - RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ - RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#if INCLUDE_JVMCI - JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ - JVMCI_PD_DEVELOP_FLAG_STRUCT, \ - JVMCI_PRODUCT_FLAG_STRUCT, \ - JVMCI_PD_PRODUCT_FLAG_STRUCT, \ - JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ - JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT, \ - JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ - JVMCI_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // INCLUDE_JVMCI -#ifdef COMPILER1 - C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ - C1_PD_DEVELOP_FLAG_STRUCT, \ - C1_PRODUCT_FLAG_STRUCT, \ - C1_PD_PRODUCT_FLAG_STRUCT, \ - C1_DIAGNOSTIC_FLAG_STRUCT, \ - C1_PD_DIAGNOSTIC_FLAG_STRUCT, \ - C1_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // COMPILER1 -#ifdef COMPILER2 - C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \ - C2_PD_DEVELOP_FLAG_STRUCT, \ - C2_PRODUCT_FLAG_STRUCT, \ - C2_PD_PRODUCT_FLAG_STRUCT, \ - C2_DIAGNOSTIC_FLAG_STRUCT, \ - C2_PD_DIAGNOSTIC_FLAG_STRUCT, \ - C2_EXPERIMENTAL_FLAG_STRUCT, \ - C2_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // COMPILER2 - ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ - ARCH_PRODUCT_FLAG_STRUCT, \ - ARCH_DIAGNOSTIC_FLAG_STRUCT, \ - ARCH_EXPERIMENTAL_FLAG_STRUCT, \ - ARCH_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) - FLAGTABLE_EXT - {0, NULL, NULL} -}; - -JVMFlag* JVMFlag::flags = flagTable; -size_t JVMFlag::numFlags = (sizeof(flagTable) / sizeof(JVMFlag)); - -inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { - if (s_len != q_len) return false; - return memcmp(s, q, q_len) == 0; -} - -// Search the flag table for a named flag -JVMFlag* JVMFlag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { - for (JVMFlag* current = &flagTable[0]; current->_name != NULL; current++) { - if (str_equal(current->_name, current->get_name_length(), name, length)) { - // Found a matching entry. - // Don't report notproduct and develop flags in product builds. - if (current->is_constant_in_binary()) { - return (return_flag ? current : NULL); - } - // Report locked flags only if allowed. - if (!(current->is_unlocked() || current->is_unlocker())) { - if (!allow_locked) { - // disable use of locked flags, e.g. diagnostic, experimental, - // commercial... until they are explicitly unlocked - return NULL; - } - } - return current; - } - } - // JVMFlag name is not in the flag table - return NULL; -} - -// Get or compute the flag name length -size_t JVMFlag::get_name_length() { - if (_name_len == 0) { - _name_len = strlen(_name); - } - return _name_len; -} - -JVMFlag* JVMFlag::fuzzy_match(const char* name, size_t length, bool allow_locked) { - float VMOptionsFuzzyMatchSimilarity = 0.7f; - JVMFlag* match = NULL; - float score; - float max_score = -1; - - for (JVMFlag* current = &flagTable[0]; current->_name != NULL; current++) { - score = StringUtils::similarity(current->_name, strlen(current->_name), name, length); - if (score > max_score) { - max_score = score; - match = current; - } - } - - if (!(match->is_unlocked() || match->is_unlocker())) { - if (!allow_locked) { - return NULL; - } - } - - if (max_score < VMOptionsFuzzyMatchSimilarity) { - return NULL; - } - - return match; -} - -// Returns the address of the index'th element -static JVMFlag* address_of_flag(JVMFlagsWithType flag) { - assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); - return &JVMFlag::flags[flag]; -} - -bool JVMFlagEx::is_default(JVMFlags flag) { - assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); - JVMFlag* f = &JVMFlag::flags[flag]; - return f->is_default(); -} - -bool JVMFlagEx::is_ergo(JVMFlags flag) { - assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); - JVMFlag* f = &JVMFlag::flags[flag]; - return f->is_ergonomic(); -} - -bool JVMFlagEx::is_cmdline(JVMFlags flag) { - assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); - JVMFlag* f = &JVMFlag::flags[flag]; - return f->is_command_line(); -} - -bool JVMFlag::wasSetOnCmdline(const char* name, bool* value) { - JVMFlag* result = JVMFlag::find_flag((char*)name, strlen(name)); - if (result == NULL) return false; - *value = result->is_command_line(); - return true; -} - -void JVMFlagEx::setOnCmdLine(JVMFlagsWithType flag) { - JVMFlag* faddr = address_of_flag(flag); - assert(faddr != NULL, "Unknown flag"); - faddr->set_command_line(); -} - -template -static void trace_flag_changed(const char* name, const T old_value, const T new_value, const JVMFlag::Flags origin) { - E e; - e.set_name(name); - e.set_oldValue(old_value); - e.set_newValue(new_value); - e.set_origin(origin); - e.commit(); -} - -static JVMFlag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_bool(new_value, verbose); - } - return status; -} - -JVMFlag::Error JVMFlag::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_bool()) return JVMFlag::WRONG_FORMAT; - *value = result->get_bool(); - return JVMFlag::SUCCESS; -} - -JVMFlag::Error JVMFlag::boolAtPut(JVMFlag* flag, bool* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_bool()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_bool(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - bool old_value = flag->get_bool(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_bool(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::boolAtPut(const char* name, size_t len, bool* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return boolAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); - return JVMFlag::boolAtPut(faddr, &value, origin); -} - -static JVMFlag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_int(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_int(new_value, verbose); - } - } - return status; -} - -JVMFlag::Error JVMFlag::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_int()) return JVMFlag::WRONG_FORMAT; - *value = result->get_int(); - return JVMFlag::SUCCESS; -} - -JVMFlag::Error JVMFlag::intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_int()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_int(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - int old_value = flag->get_int(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_int(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::intAtPut(const char* name, size_t len, int* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return intAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_int(), "wrong flag type"); - return JVMFlag::intAtPut(faddr, &value, origin); -} - -static JVMFlag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uint(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uint(new_value, verbose); - } - } - return status; -} - -JVMFlag::Error JVMFlag::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_uint()) return JVMFlag::WRONG_FORMAT; - *value = result->get_uint(); - return JVMFlag::SUCCESS; -} - -JVMFlag::Error JVMFlag::uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_uint()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_uint(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - uint old_value = flag->get_uint(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::uintAtPut(const char* name, size_t len, uint* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return uintAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type"); - return JVMFlag::uintAtPut(faddr, &value, origin); -} - -JVMFlag::Error JVMFlag::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_intx()) return JVMFlag::WRONG_FORMAT; - *value = result->get_intx(); - return JVMFlag::SUCCESS; -} - -static JVMFlag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_intx(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_intx(new_value, verbose); - } - } - return status; -} - -JVMFlag::Error JVMFlag::intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_intx()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_intx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - intx old_value = flag->get_intx(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_intx(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::intxAtPut(const char* name, size_t len, intx* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return intxAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); - return JVMFlag::intxAtPut(faddr, &value, origin); -} - -JVMFlag::Error JVMFlag::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_uintx()) return JVMFlag::WRONG_FORMAT; - *value = result->get_uintx(); - return JVMFlag::SUCCESS; -} - -static JVMFlag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uintx(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uintx(new_value, verbose); - } - } - return status; -} - -JVMFlag::Error JVMFlag::uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_uintx()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_uintx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - uintx old_value = flag->get_uintx(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uintx(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::uintxAtPut(const char* name, size_t len, uintx* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return uintxAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); - return JVMFlag::uintxAtPut(faddr, &value, origin); -} - -JVMFlag::Error JVMFlag::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_uint64_t()) return JVMFlag::WRONG_FORMAT; - *value = result->get_uint64_t(); - return JVMFlag::SUCCESS; -} - -static JVMFlag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uint64_t(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uint64_t(new_value, verbose); - } - } - return status; -} - -JVMFlag::Error JVMFlag::uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_uint64_t()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - uint64_t old_value = flag->get_uint64_t(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint64_t(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::uint64_tAtPut(const char* name, size_t len, uint64_t* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return uint64_tAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); - return JVMFlag::uint64_tAtPut(faddr, &value, origin); -} - -JVMFlag::Error JVMFlag::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_size_t()) return JVMFlag::WRONG_FORMAT; - *value = result->get_size_t(); - return JVMFlag::SUCCESS; -} - -static JVMFlag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_size_t(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_size_t(new_value, verbose); - } - } - return status; -} - - -JVMFlag::Error JVMFlag::size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_size_t()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_size_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - size_t old_value = flag->get_size_t(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_size_t(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::size_tAtPut(const char* name, size_t len, size_t* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return size_tAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); - return JVMFlag::size_tAtPut(faddr, &value, origin); -} - -JVMFlag::Error JVMFlag::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_double()) return JVMFlag::WRONG_FORMAT; - *value = result->get_double(); - return JVMFlag::SUCCESS; -} - -static JVMFlag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) { - JVMFlag::Error status = JVMFlag::SUCCESS; - JVMFlagRange* range = JVMFlagRangeList::find(name); - if (range != NULL) { - status = range->check_double(new_value, verbose); - } - if (status == JVMFlag::SUCCESS) { - JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_double(new_value, verbose); - } - } - return status; -} - -JVMFlag::Error JVMFlag::doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags origin) { - const char* name; - if (flag == NULL) return JVMFlag::INVALID_FLAG; - if (!flag->is_double()) return JVMFlag::WRONG_FORMAT; - name = flag->_name; - JVMFlag::Error check = apply_constraint_and_check_range_double(name, *value, !JVMFlagConstraintList::validated_after_ergo()); - if (check != JVMFlag::SUCCESS) return check; - double old_value = flag->get_double(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_double(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlag::doubleAtPut(const char* name, size_t len, double* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - return doubleAtPut(result, value, origin); -} - -JVMFlag::Error JVMFlagEx::doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); - return JVMFlag::doubleAtPut(faddr, &value, origin); -} - -JVMFlag::Error JVMFlag::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) { - JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_ccstr()) return JVMFlag::WRONG_FORMAT; - *value = result->get_ccstr(); - return JVMFlag::SUCCESS; -} - -JVMFlag::Error JVMFlag::ccstrAtPut(const char* name, size_t len, ccstr* value, JVMFlag::Flags origin) { - JVMFlag* result = JVMFlag::find_flag(name, len); - if (result == NULL) return JVMFlag::INVALID_FLAG; - if (!result->is_ccstr()) return JVMFlag::WRONG_FORMAT; - ccstr old_value = result->get_ccstr(); - trace_flag_changed(name, old_value, *value, origin); - char* new_value = NULL; - if (*value != NULL) { - new_value = os::strdup_check_oom(*value); - } - JVMFlag::Error check = result->set_ccstr(new_value); - if (result->is_default() && old_value != NULL) { - // Prior value is NOT heap allocated, but was a literal constant. - old_value = os::strdup_check_oom(old_value); - } - *value = old_value; - result->set_origin(origin); - return check; -} - -JVMFlag::Error JVMFlagEx::ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin) { - JVMFlag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); - ccstr old_value = faddr->get_ccstr(); - trace_flag_changed(faddr->_name, old_value, value, origin); - char* new_value = os::strdup_check_oom(value); - JVMFlag::Error check = faddr->set_ccstr(new_value); - if (!faddr->is_default() && old_value != NULL) { - // Prior value is heap allocated so free it. - FREE_C_HEAP_ARRAY(char, old_value); - } - faddr->set_origin(origin); - return check; -} - -extern "C" { - static int compare_flags(const void* void_a, const void* void_b) { - return strcmp((*((JVMFlag**) void_a))->_name, (*((JVMFlag**) void_b))->_name); - } -} - -void JVMFlag::printSetFlags(outputStream* out) { - // Print which flags were set on the command line - // note: this method is called before the thread structure is in place - // which means resource allocation cannot be used. - - // The last entry is the null entry. - const size_t length = JVMFlag::numFlags - 1; - - // Sort - JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(JVMFlag*), compare_flags); - - // Print - for (size_t i = 0; i < length; i++) { - if (array[i]->get_origin() /* naked field! */) { - array[i]->print_as_flag(out); - out->print(" "); - } - } - out->cr(); - FREE_C_HEAP_ARRAY(JVMFlag*, array); -} - -#ifndef PRODUCT - -void JVMFlag::verify() { - assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); -} - -#endif // PRODUCT - -void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges) { - // Print the flags sorted by name - // note: this method is called before the thread structure is in place - // which means resource allocation cannot be used. - - // The last entry is the null entry. - const size_t length = JVMFlag::numFlags - 1; - - // Sort - JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(JVMFlag*), compare_flags); - - // Print - if (!printRanges) { - out->print_cr("[Global flags]"); - } else { - out->print_cr("[Global flags ranges]"); - } - - for (size_t i = 0; i < length; i++) { - if (array[i]->is_unlocked()) { - array[i]->print_on(out, withComments, printRanges); - } - } - FREE_C_HEAP_ARRAY(JVMFlag*, array); -} - diff --git a/src/hotspot/share/runtime/flags/jvmFlag.hpp b/src/hotspot/share/runtime/flags/jvmFlag.hpp deleted file mode 100644 index e8c8210bd06..00000000000 --- a/src/hotspot/share/runtime/flags/jvmFlag.hpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP -#define SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" - -// function type that will construct default range string -typedef const char* (*RangeStrFunc)(void); - -struct JVMFlag { - enum Flags { - // latest value origin - DEFAULT = 0, - COMMAND_LINE = 1, - ENVIRON_VAR = 2, - CONFIG_FILE = 3, - MANAGEMENT = 4, - ERGONOMIC = 5, - ATTACH_ON_DEMAND = 6, - INTERNAL = 7, - - LAST_VALUE_ORIGIN = INTERNAL, - VALUE_ORIGIN_BITS = 4, - VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), - - // flag kind - KIND_PRODUCT = 1 << 4, - KIND_MANAGEABLE = 1 << 5, - KIND_DIAGNOSTIC = 1 << 6, - KIND_EXPERIMENTAL = 1 << 7, - KIND_NOT_PRODUCT = 1 << 8, - KIND_DEVELOP = 1 << 9, - KIND_PLATFORM_DEPENDENT = 1 << 10, - KIND_READ_WRITE = 1 << 11, - KIND_C1 = 1 << 12, - KIND_C2 = 1 << 13, - KIND_ARCH = 1 << 14, - KIND_LP64_PRODUCT = 1 << 15, - KIND_COMMERCIAL = 1 << 16, - KIND_JVMCI = 1 << 17, - - // set this bit if the flag was set on the command line - ORIG_COMMAND_LINE = 1 << 18, - - KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) - }; - - enum Error { - // no error - SUCCESS = 0, - // flag name is missing - MISSING_NAME, - // flag value is missing - MISSING_VALUE, - // error parsing the textual form of the value - WRONG_FORMAT, - // flag is not writable - NON_WRITABLE, - // flag value is outside of its bounds - OUT_OF_BOUNDS, - // flag value violates its constraint - VIOLATES_CONSTRAINT, - // there is no flag with the given name - INVALID_FLAG, - // the flag can only be set only on command line during invocation of the VM - COMMAND_LINE_ONLY, - // the flag may only be set once - SET_ONLY_ONCE, - // the flag is not writable in this combination of product/debug build - CONSTANT, - // other, unspecified error related to setting the flag - ERR_OTHER - }; - - enum MsgType { - NONE = 0, - DIAGNOSTIC_FLAG_BUT_LOCKED, - EXPERIMENTAL_FLAG_BUT_LOCKED, - DEVELOPER_FLAG_BUT_PRODUCT_BUILD, - NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD, - COMMERCIAL_FLAG_BUT_DISABLED, - COMMERCIAL_FLAG_BUT_LOCKED - }; - - const char* _type; - const char* _name; - void* _addr; - NOT_PRODUCT(const char* _doc;) - Flags _flags; - size_t _name_len; - - // points to all Flags static array - static JVMFlag* flags; - - // number of flags - static size_t numFlags; - - static JVMFlag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); }; - static JVMFlag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); - static JVMFlag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); - - static const char* get_int_default_range_str(); - static const char* get_uint_default_range_str(); - static const char* get_intx_default_range_str(); - static const char* get_uintx_default_range_str(); - static const char* get_uint64_t_default_range_str(); - static const char* get_size_t_default_range_str(); - static const char* get_double_default_range_str(); - - JVMFlag::Error check_writable(bool changed); - - bool is_bool() const; - bool get_bool() const; - JVMFlag::Error set_bool(bool value); - - bool is_int() const; - int get_int() const; - JVMFlag::Error set_int(int value); - - bool is_uint() const; - uint get_uint() const; - JVMFlag::Error set_uint(uint value); - - bool is_intx() const; - intx get_intx() const; - JVMFlag::Error set_intx(intx value); - - bool is_uintx() const; - uintx get_uintx() const; - JVMFlag::Error set_uintx(uintx value); - - bool is_uint64_t() const; - uint64_t get_uint64_t() const; - JVMFlag::Error set_uint64_t(uint64_t value); - - bool is_size_t() const; - size_t get_size_t() const; - JVMFlag::Error set_size_t(size_t value); - - bool is_double() const; - double get_double() const; - JVMFlag::Error set_double(double value); - - bool is_ccstr() const; - bool ccstr_accumulates() const; - ccstr get_ccstr() const; - JVMFlag::Error set_ccstr(ccstr value); - - Flags get_origin(); - void set_origin(Flags origin); - - size_t get_name_length(); - - bool is_default(); - bool is_ergonomic(); - bool is_command_line(); - void set_command_line(); - - bool is_product() const; - bool is_manageable() const; - bool is_diagnostic() const; - bool is_experimental() const; - bool is_notproduct() const; - bool is_develop() const; - bool is_read_write() const; - bool is_commercial() const; - - bool is_constant_in_binary() const; - - bool is_unlocker() const; - bool is_unlocked() const; - bool is_writeable() const; - bool is_external() const; - - bool is_unlocker_ext() const; - bool is_unlocked_ext() const; - bool is_writeable_ext() const; - bool is_external_ext() const; - - void clear_diagnostic(); - - JVMFlag::MsgType get_locked_message(char*, int) const; - JVMFlag::MsgType get_locked_message_ext(char*, int) const; - - // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges - void print_on(outputStream* st, bool withComments = false, bool printRanges = false); - void print_kind(outputStream* st, unsigned int width); - void print_origin(outputStream* st, unsigned int width); - void print_as_flag(outputStream* st); - - static const char* flag_error_str(JVMFlag::Error error); - -public: - static JVMFlag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error boolAtPut(JVMFlag* flag, bool* value, JVMFlag::Flags origin); - static JVMFlag::Error boolAtPut(const char* name, size_t len, bool* value, JVMFlag::Flags origin); - static JVMFlag::Error boolAtPut(const char* name, bool* value, JVMFlag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origin); - static JVMFlag::Error intAtPut(const char* name, size_t len, int* value, JVMFlag::Flags origin); - static JVMFlag::Error intAtPut(const char* name, int* value, JVMFlag::Flags origin) { return intAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags origin); - static JVMFlag::Error uintAtPut(const char* name, size_t len, uint* value, JVMFlag::Flags origin); - static JVMFlag::Error uintAtPut(const char* name, uint* value, JVMFlag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags origin); - static JVMFlag::Error intxAtPut(const char* name, size_t len, intx* value, JVMFlag::Flags origin); - static JVMFlag::Error intxAtPut(const char* name, intx* value, JVMFlag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags origin); - static JVMFlag::Error uintxAtPut(const char* name, size_t len, uintx* value, JVMFlag::Flags origin); - static JVMFlag::Error uintxAtPut(const char* name, uintx* value, JVMFlag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin); - static JVMFlag::Error size_tAtPut(const char* name, size_t len, size_t* value, JVMFlag::Flags origin); - static JVMFlag::Error size_tAtPut(const char* name, size_t* value, JVMFlag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::Flags origin); - static JVMFlag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, JVMFlag::Flags origin); - static JVMFlag::Error uint64_tAtPut(const char* name, uint64_t* value, JVMFlag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); } - static JVMFlag::Error doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags origin); - static JVMFlag::Error doubleAtPut(const char* name, size_t len, double* value, JVMFlag::Flags origin); - static JVMFlag::Error doubleAtPut(const char* name, double* value, JVMFlag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } - - static JVMFlag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false); - static JVMFlag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); } - // Contract: JVMFlag will make private copy of the incoming value. - // Outgoing value is always malloc-ed, and caller MUST call free. - static JVMFlag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, JVMFlag::Flags origin); - static JVMFlag::Error ccstrAtPut(const char* name, ccstr* value, JVMFlag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } - - // Returns false if name is not a command line flag. - static bool wasSetOnCmdline(const char* name, bool* value); - static void printSetFlags(outputStream* out); - - // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges - static void printFlags(outputStream* out, bool withComments, bool printRanges = false); - - static void verify() PRODUCT_RETURN; -}; - -#endif // SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp deleted file mode 100644 index 9c27f1db955..00000000000 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP -#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP - -#include "runtime/flags/jvmFlag.hpp" -#include "utilities/growableArray.hpp" - -/* - * Here we have a mechanism for extracting constraints (as custom functions) for flags, - * which otherwise can not be expressed via simple range check, specified in flag macro tables. - * - * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change. - * - * See runtime "runtime/flags/jvmFlagConstraintsCompiler.hpp", - * "runtime/flags/jvmFlagConstraintsGC.hpp" and - * "runtime/flags/jvmFlagConstraintsRuntime.hpp" for the functions themselves. - */ - -typedef JVMFlag::Error (*JVMFlagConstraintFunc_bool)(bool value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_int)(int value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_intx)(intx value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint)(uint value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_uintx)(uintx value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_size_t)(size_t value, bool verbose); -typedef JVMFlag::Error (*JVMFlagConstraintFunc_double)(double value, bool verbose); - -class JVMFlagConstraint : public CHeapObj { -public: - // During VM initialization, constraint validation will be done order of ConstraintType. - enum ConstraintType { - // Will be validated during argument processing (Arguments::parse_argument). - AtParse = 0, - // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). - AfterErgo = 1, - // Will be validated inside universe_init(), right after Metaspace::global_initialize(). - AfterMemoryInit = 2 - }; - -private: - const char* _name; - ConstraintType _validate_type; - -public: - // the "name" argument must be a string literal - JVMFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; - ~JVMFlagConstraint() {}; - const char* name() const { return _name; } - ConstraintType type() const { return _validate_type; } - virtual JVMFlag::Error apply(bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; - virtual JVMFlag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; -}; - -class JVMFlagConstraintList : public AllStatic { -private: - static GrowableArray* _constraints; - // Latest constraint validation type. - static JVMFlagConstraint::ConstraintType _validating_type; -public: - static void init(); - static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } - static JVMFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } - static JVMFlagConstraint* find(const char* name); - static JVMFlagConstraint* find_if_needs_check(const char* name); - static void add(JVMFlagConstraint* constraint) { _constraints->append(constraint); } - // True if 'AfterErgo' or later constraint functions are validated. - static bool validated_after_ergo() { return _validating_type >= JVMFlagConstraint::AfterErgo; }; - static bool check_constraints(JVMFlagConstraint::ConstraintType type); -}; - -#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP */ diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp deleted file mode 100644 index f18b1269ed1..00000000000 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP -#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP - -#include "runtime/flags/jvmFlag.hpp" - -/* - * Here we have compiler arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose); - -JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose); - -JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); - -JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); - -JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); - -JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose); - -JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); - -JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); - -JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); - -JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); - -JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); - -JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); - -JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); - -JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); - -JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose); - -#ifdef COMPILER2 -JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); - -JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); -#endif - -JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose); - -#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/src/hotspot/share/runtime/globals.cpp b/src/hotspot/share/runtime/globals.cpp index 3ee7d90df44..16054f408b1 100644 --- a/src/hotspot/share/runtime/globals.cpp +++ b/src/hotspot/share/runtime/globals.cpp @@ -29,9 +29,9 @@ #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" -#include "runtime/flags/jvmFlagWriteableList.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/commandLineFlagWriteableList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "trace/tracing.hpp" @@ -85,3 +85,1473 @@ ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ IGNORE_WRITEABLE) MATERIALIZE_FLAGS_EXT + +#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 +static char* create_range_str(const char *fmt, ...) { + static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; + static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); + + int size_needed = 0; + do { + va_list args; + va_start(args, fmt); + size_needed = jio_vsnprintf(range_string, string_length, fmt, args); + va_end(args); + + if (size_needed < 0) { + string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; + range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); + guarantee(range_string != NULL, "create_range_str string should not be NULL"); + } + } while (size_needed < 0); + + return range_string; +} + +const char* Flag::get_int_default_range_str() { + return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); +} + +const char* Flag::get_uint_default_range_str() { + return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); +} + +const char* Flag::get_intx_default_range_str() { + return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); +} + +const char* Flag::get_uintx_default_range_str() { + return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); +} + +const char* Flag::get_uint64_t_default_range_str() { + return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); +} + +const char* Flag::get_size_t_default_range_str() { + return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); +} + +const char* Flag::get_double_default_range_str() { + return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); +} + +static bool is_product_build() { +#ifdef PRODUCT + return true; +#else + return false; +#endif +} + +Flag::Error Flag::check_writable(bool changed) { + if (is_constant_in_binary()) { + fatal("flag is constant: %s", _name); + } + + Flag::Error error = Flag::SUCCESS; + if (changed) { + CommandLineFlagWriteable* writeable = CommandLineFlagWriteableList::find(_name); + if (writeable) { + if (writeable->is_writeable() == false) { + switch (writeable->type()) + { + case CommandLineFlagWriteable::Once: + error = Flag::SET_ONLY_ONCE; + jio_fprintf(defaultStream::error_stream(), "Error: %s may not be set more than once\n", _name); + break; + case CommandLineFlagWriteable::CommandLineOnly: + error = Flag::COMMAND_LINE_ONLY; + jio_fprintf(defaultStream::error_stream(), "Error: %s may be modified only from commad line\n", _name); + break; + default: + ShouldNotReachHere(); + break; + } + } + writeable->mark_once(); + } + } + return error; +} + +bool Flag::is_bool() const { + return strcmp(_type, "bool") == 0; +} + +bool Flag::get_bool() const { + return *((bool*) _addr); +} + +Flag::Error Flag::set_bool(bool value) { + Flag::Error error = check_writable(value!=get_bool()); + if (error == Flag::SUCCESS) { + *((bool*) _addr) = value; + } + return error; +} + +bool Flag::is_int() const { + return strcmp(_type, "int") == 0; +} + +int Flag::get_int() const { + return *((int*) _addr); +} + +Flag::Error Flag::set_int(int value) { + Flag::Error error = check_writable(value!=get_int()); + if (error == Flag::SUCCESS) { + *((int*) _addr) = value; + } + return error; +} + +bool Flag::is_uint() const { + return strcmp(_type, "uint") == 0; +} + +uint Flag::get_uint() const { + return *((uint*) _addr); +} + +Flag::Error Flag::set_uint(uint value) { + Flag::Error error = check_writable(value!=get_uint()); + if (error == Flag::SUCCESS) { + *((uint*) _addr) = value; + } + return error; +} + +bool Flag::is_intx() const { + return strcmp(_type, "intx") == 0; +} + +intx Flag::get_intx() const { + return *((intx*) _addr); +} + +Flag::Error Flag::set_intx(intx value) { + Flag::Error error = check_writable(value!=get_intx()); + if (error == Flag::SUCCESS) { + *((intx*) _addr) = value; + } + return error; +} + +bool Flag::is_uintx() const { + return strcmp(_type, "uintx") == 0; +} + +uintx Flag::get_uintx() const { + return *((uintx*) _addr); +} + +Flag::Error Flag::set_uintx(uintx value) { + Flag::Error error = check_writable(value!=get_uintx()); + if (error == Flag::SUCCESS) { + *((uintx*) _addr) = value; + } + return error; +} + +bool Flag::is_uint64_t() const { + return strcmp(_type, "uint64_t") == 0; +} + +uint64_t Flag::get_uint64_t() const { + return *((uint64_t*) _addr); +} + +Flag::Error Flag::set_uint64_t(uint64_t value) { + Flag::Error error = check_writable(value!=get_uint64_t()); + if (error == Flag::SUCCESS) { + *((uint64_t*) _addr) = value; + } + return error; +} + +bool Flag::is_size_t() const { + return strcmp(_type, "size_t") == 0; +} + +size_t Flag::get_size_t() const { + return *((size_t*) _addr); +} + +Flag::Error Flag::set_size_t(size_t value) { + Flag::Error error = check_writable(value!=get_size_t()); + if (error == Flag::SUCCESS) { + *((size_t*) _addr) = value; + } + return error; +} + +bool Flag::is_double() const { + return strcmp(_type, "double") == 0; +} + +double Flag::get_double() const { + return *((double*) _addr); +} + +Flag::Error Flag::set_double(double value) { + Flag::Error error = check_writable(value!=get_double()); + if (error == Flag::SUCCESS) { + *((double*) _addr) = value; + } + return error; +} + +bool Flag::is_ccstr() const { + return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; +} + +bool Flag::ccstr_accumulates() const { + return strcmp(_type, "ccstrlist") == 0; +} + +ccstr Flag::get_ccstr() const { + return *((ccstr*) _addr); +} + +Flag::Error Flag::set_ccstr(ccstr value) { + Flag::Error error = check_writable(value!=get_ccstr()); + if (error == Flag::SUCCESS) { + *((ccstr*) _addr) = value; + } + return error; +} + + +Flag::Flags Flag::get_origin() { + return Flags(_flags & VALUE_ORIGIN_MASK); +} + +void Flag::set_origin(Flags origin) { + assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); + Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); + _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); +} + +bool Flag::is_default() { + return (get_origin() == DEFAULT); +} + +bool Flag::is_ergonomic() { + return (get_origin() == ERGONOMIC); +} + +bool Flag::is_command_line() { + return (_flags & ORIG_COMMAND_LINE) != 0; +} + +void Flag::set_command_line() { + _flags = Flags(_flags | ORIG_COMMAND_LINE); +} + +bool Flag::is_product() const { + return (_flags & KIND_PRODUCT) != 0; +} + +bool Flag::is_manageable() const { + return (_flags & KIND_MANAGEABLE) != 0; +} + +bool Flag::is_diagnostic() const { + return (_flags & KIND_DIAGNOSTIC) != 0; +} + +bool Flag::is_experimental() const { + return (_flags & KIND_EXPERIMENTAL) != 0; +} + +bool Flag::is_notproduct() const { + return (_flags & KIND_NOT_PRODUCT) != 0; +} + +bool Flag::is_develop() const { + return (_flags & KIND_DEVELOP) != 0; +} + +bool Flag::is_read_write() const { + return (_flags & KIND_READ_WRITE) != 0; +} + +bool Flag::is_commercial() const { + return (_flags & KIND_COMMERCIAL) != 0; +} + +/** + * Returns if this flag is a constant in the binary. Right now this is + * true for notproduct and develop flags in product builds. + */ +bool Flag::is_constant_in_binary() const { +#ifdef PRODUCT + return is_notproduct() || is_develop(); +#else + return false; +#endif +} + +bool Flag::is_unlocker() const { + return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || + strcmp(_name, "UnlockExperimentalVMOptions") == 0 || + is_unlocker_ext(); +} + +bool Flag::is_unlocked() const { + if (is_diagnostic()) { + return UnlockDiagnosticVMOptions; + } + if (is_experimental()) { + return UnlockExperimentalVMOptions; + } + return is_unlocked_ext(); +} + +void Flag::clear_diagnostic() { + assert(is_diagnostic(), "sanity"); + _flags = Flags(_flags & ~KIND_DIAGNOSTIC); + assert(!is_diagnostic(), "sanity"); +} + +// Get custom message for this locked flag, or NULL if +// none is available. Returns message type produced. +Flag::MsgType Flag::get_locked_message(char* buf, int buflen) const { + buf[0] = '\0'; + if (is_diagnostic() && !is_unlocked()) { + jio_snprintf(buf, buflen, + "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" + "Error: The unlock option must precede '%s'.\n", + _name, _name); + return Flag::DIAGNOSTIC_FLAG_BUT_LOCKED; + } + if (is_experimental() && !is_unlocked()) { + jio_snprintf(buf, buflen, + "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" + "Error: The unlock option must precede '%s'.\n", + _name, _name); + return Flag::EXPERIMENTAL_FLAG_BUT_LOCKED; + } + if (is_develop() && is_product_build()) { + jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", + _name); + return Flag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; + } + if (is_notproduct() && is_product_build()) { + jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", + _name); + return Flag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; + } + return get_locked_message_ext(buf, buflen); +} + +bool Flag::is_writeable() const { + return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); +} + +// All flags except "manageable" are assumed to be internal flags. +// Long term, we need to define a mechanism to specify which flags +// are external/stable and change this function accordingly. +bool Flag::is_external() const { + return is_manageable() || is_external_ext(); +} + +// Helper function for Flag::print_on(). +// Fills current line up to requested position. +// Should the current position already be past the requested position, +// one separator blank is enforced. +void fill_to_pos(outputStream* st, unsigned int req_pos) { + if ((unsigned int)st->position() < req_pos) { + st->fill_to(req_pos); // need to fill with blanks to reach req_pos + } else { + st->print(" "); // enforce blank separation. Previous field too long. + } +} + +void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { + // Don't print notproduct and develop flags in a product build. + if (is_constant_in_binary()) { + return; + } + + if (!printRanges) { + // The command line options -XX:+PrintFlags* cause this function to be called + // for each existing flag to print information pertinent to this flag. The data + // is displayed in columnar form, with the following layout: + // col1 - data type, right-justified + // col2 - name, left-justified + // col3 - ' =' double-char, leading space to align with possible '+=' + // col4 - value left-justified + // col5 - kind right-justified + // col6 - origin left-justified + // col7 - comments left-justified + // + // The column widths are fixed. They are defined such that, for most cases, + // an eye-pleasing tabular output is created. + // + // Sample output: + // bool CMSScavengeBeforeRemark = false {product} {default} + // uintx CMSScheduleRemarkEdenPenetration = 50 {product} {default} + // size_t CMSScheduleRemarkEdenSizeThreshold = 2097152 {product} {default} + // uintx CMSScheduleRemarkSamplingRatio = 5 {product} {default} + // double CMSSmallCoalSurplusPercent = 1.050000 {product} {default} + // ccstr CompileCommandFile = MyFile.cmd {product} {command line} + // ccstrlist CompileOnly = Method1 + // CompileOnly += Method2 {product} {command line} + // | | | | | | | + // | | | | | | +-- col7 + // | | | | | +-- col6 + // | | | | +-- col5 + // | | | +-- col4 + // | | +-- col3 + // | +-- col2 + // +-- col1 + + const unsigned int col_spacing = 1; + const unsigned int col1_pos = 0; + const unsigned int col1_width = 9; + const unsigned int col2_pos = col1_pos + col1_width + col_spacing; + const unsigned int col2_width = 39; + const unsigned int col3_pos = col2_pos + col2_width + col_spacing; + const unsigned int col3_width = 2; + const unsigned int col4_pos = col3_pos + col3_width + col_spacing; + const unsigned int col4_width = 30; + const unsigned int col5_pos = col4_pos + col4_width + col_spacing; + const unsigned int col5_width = 20; + const unsigned int col6_pos = col5_pos + col5_width + col_spacing; + const unsigned int col6_width = 15; + const unsigned int col7_pos = col6_pos + col6_width + col_spacing; + const unsigned int col7_width = 1; + + st->fill_to(col1_pos); + st->print("%*s", col1_width, _type); // right-justified, therefore width is required. + + fill_to_pos(st, col2_pos); + st->print("%s", _name); + + fill_to_pos(st, col3_pos); + st->print(" ="); // use " =" for proper alignment with multiline ccstr output. + + fill_to_pos(st, col4_pos); + if (is_bool()) { + st->print("%s", get_bool() ? "true" : "false"); + } else if (is_int()) { + st->print("%d", get_int()); + } else if (is_uint()) { + st->print("%u", get_uint()); + } else if (is_intx()) { + st->print(INTX_FORMAT, get_intx()); + } else if (is_uintx()) { + st->print(UINTX_FORMAT, get_uintx()); + } else if (is_uint64_t()) { + st->print(UINT64_FORMAT, get_uint64_t()); + } else if (is_size_t()) { + st->print(SIZE_FORMAT, get_size_t()); + } else if (is_double()) { + st->print("%f", get_double()); + } else if (is_ccstr()) { + // Honor characters in ccstr: print multiple lines. + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + size_t llen = pointer_delta(eol, cp, sizeof(char)); + st->print("%.*s", (int)llen, cp); + st->cr(); + cp = eol+1; + fill_to_pos(st, col2_pos); + st->print("%s", _name); + fill_to_pos(st, col3_pos); + st->print("+="); + fill_to_pos(st, col4_pos); + } + st->print("%s", cp); + } + } else { + st->print("unhandled type %s", _type); + st->cr(); + return; + } + + fill_to_pos(st, col5_pos); + print_kind(st, col5_width); + + fill_to_pos(st, col6_pos); + print_origin(st, col6_width); + +#ifndef PRODUCT + if (withComments) { + fill_to_pos(st, col7_pos); + st->print("%s", _doc); + } +#endif + st->cr(); + } else if (!is_bool() && !is_ccstr()) { + // The command line options -XX:+PrintFlags* cause this function to be called + // for each existing flag to print information pertinent to this flag. The data + // is displayed in columnar form, with the following layout: + // col1 - data type, right-justified + // col2 - name, left-justified + // col4 - range [ min ... max] + // col5 - kind right-justified + // col6 - origin left-justified + // col7 - comments left-justified + // + // The column widths are fixed. They are defined such that, for most cases, + // an eye-pleasing tabular output is created. + // + // Sample output: + // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} + // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} + // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} + // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} + // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} + // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} + // | | | | | | + // | | | | | +-- col7 + // | | | | +-- col6 + // | | | +-- col5 + // | | +-- col4 + // | +-- col2 + // +-- col1 + + const unsigned int col_spacing = 1; + const unsigned int col1_pos = 0; + const unsigned int col1_width = 9; + const unsigned int col2_pos = col1_pos + col1_width + col_spacing; + const unsigned int col2_width = 49; + const unsigned int col3_pos = col2_pos + col2_width + col_spacing; + const unsigned int col3_width = 0; + const unsigned int col4_pos = col3_pos + col3_width + col_spacing; + const unsigned int col4_width = 60; + const unsigned int col5_pos = col4_pos + col4_width + col_spacing; + const unsigned int col5_width = 35; + const unsigned int col6_pos = col5_pos + col5_width + col_spacing; + const unsigned int col6_width = 15; + const unsigned int col7_pos = col6_pos + col6_width + col_spacing; + const unsigned int col7_width = 1; + + st->fill_to(col1_pos); + st->print("%*s", col1_width, _type); // right-justified, therefore width is required. + + fill_to_pos(st, col2_pos); + st->print("%s", _name); + + fill_to_pos(st, col4_pos); + RangeStrFunc func = NULL; + if (is_int()) { + func = Flag::get_int_default_range_str; + } else if (is_uint()) { + func = Flag::get_uint_default_range_str; + } else if (is_intx()) { + func = Flag::get_intx_default_range_str; + } else if (is_uintx()) { + func = Flag::get_uintx_default_range_str; + } else if (is_uint64_t()) { + func = Flag::get_uint64_t_default_range_str; + } else if (is_size_t()) { + func = Flag::get_size_t_default_range_str; + } else if (is_double()) { + func = Flag::get_double_default_range_str; + } else { + st->print("unhandled type %s", _type); + st->cr(); + return; + } + CommandLineFlagRangeList::print(st, _name, func); + + fill_to_pos(st, col5_pos); + print_kind(st, col5_width); + + fill_to_pos(st, col6_pos); + print_origin(st, col6_width); + +#ifndef PRODUCT + if (withComments) { + fill_to_pos(st, col7_pos); + st->print("%s", _doc); + } +#endif + st->cr(); + } +} + +void Flag::print_kind(outputStream* st, unsigned int width) { + struct Data { + int flag; + const char* name; + }; + + Data data[] = { + { KIND_JVMCI, "JVMCI" }, + { KIND_C1, "C1" }, + { KIND_C2, "C2" }, + { KIND_ARCH, "ARCH" }, + { KIND_PLATFORM_DEPENDENT, "pd" }, + { KIND_PRODUCT, "product" }, + { KIND_MANAGEABLE, "manageable" }, + { KIND_DIAGNOSTIC, "diagnostic" }, + { KIND_EXPERIMENTAL, "experimental" }, + { KIND_COMMERCIAL, "commercial" }, + { KIND_NOT_PRODUCT, "notproduct" }, + { KIND_DEVELOP, "develop" }, + { KIND_LP64_PRODUCT, "lp64_product" }, + { KIND_READ_WRITE, "rw" }, + { -1, "" } + }; + + if ((_flags & KIND_MASK) != 0) { + bool is_first = true; + const size_t buffer_size = 64; + size_t buffer_used = 0; + char kind[buffer_size]; + + jio_snprintf(kind, buffer_size, "{"); + buffer_used++; + for (int i = 0; data[i].flag != -1; i++) { + Data d = data[i]; + if ((_flags & d.flag) != 0) { + if (is_first) { + is_first = false; + } else { + assert(buffer_used + 1 < buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); + buffer_used++; + } + size_t length = strlen(d.name); + assert(buffer_used + length < buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); + buffer_used += length; + } + } + assert(buffer_used + 2 <= buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); + st->print("%*s", width, kind); + } +} + +void Flag::print_origin(outputStream* st, unsigned int width) { + int origin = _flags & VALUE_ORIGIN_MASK; + st->print("{"); + switch(origin) { + case DEFAULT: + st->print("default"); break; + case COMMAND_LINE: + st->print("command line"); break; + case ENVIRON_VAR: + st->print("environment"); break; + case CONFIG_FILE: + st->print("config file"); break; + case MANAGEMENT: + st->print("management"); break; + case ERGONOMIC: + if (_flags & ORIG_COMMAND_LINE) { + st->print("command line, "); + } + st->print("ergonomic"); break; + case ATTACH_ON_DEMAND: + st->print("attach"); break; + case INTERNAL: + st->print("internal"); break; + } + st->print("}"); +} + +void Flag::print_as_flag(outputStream* st) { + if (is_bool()) { + st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); + } else if (is_int()) { + st->print("-XX:%s=%d", _name, get_int()); + } else if (is_uint()) { + st->print("-XX:%s=%u", _name, get_uint()); + } else if (is_intx()) { + st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); + } else if (is_uintx()) { + st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); + } else if (is_uint64_t()) { + st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); + } else if (is_size_t()) { + st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); + } else if (is_double()) { + st->print("-XX:%s=%f", _name, get_double()); + } else if (is_ccstr()) { + st->print("-XX:%s=", _name); + const char* cp = get_ccstr(); + if (cp != NULL) { + // Need to turn embedded '\n's back into separate arguments + // Not so efficient to print one character at a time, + // but the choice is to do the transformation to a buffer + // and print that. And this need not be efficient. + for (; *cp != '\0'; cp += 1) { + switch (*cp) { + default: + st->print("%c", *cp); + break; + case '\n': + st->print(" -XX:%s=", _name); + break; + } + } + } + } else { + ShouldNotReachHere(); + } +} + +const char* Flag::flag_error_str(Flag::Error error) { + switch (error) { + case Flag::MISSING_NAME: return "MISSING_NAME"; + case Flag::MISSING_VALUE: return "MISSING_VALUE"; + case Flag::NON_WRITABLE: return "NON_WRITABLE"; + case Flag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; + case Flag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; + case Flag::INVALID_FLAG: return "INVALID_FLAG"; + case Flag::ERR_OTHER: return "ERR_OTHER"; + case Flag::SUCCESS: return "SUCCESS"; + default: ShouldNotReachHere(); return "NULL"; + } +} + +// 4991491 do not "optimize out" the was_set false values: omitting them +// tickles a Microsoft compiler bug causing flagTable to be malformed + +#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT) }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC) }, +#define RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_EXPERIMENTAL) }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_MANAGEABLE) }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_READ_WRITE) }, +#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP) }, +#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, + +#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT) }, +#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC) }, +#define JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_EXPERIMENTAL) }, +#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP) }, +#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_NOT_PRODUCT) }, + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, +#else +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ +#endif // _LP64 + +#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT) }, +#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC) }, +#define C1_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP) }, +#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_NOT_PRODUCT) }, + +#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT) }, +#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC) }, +#define C2_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_EXPERIMENTAL) }, +#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP) }, +#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_NOT_PRODUCT) }, + +#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_PRODUCT) }, +#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DIAGNOSTIC) }, +#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_EXPERIMENTAL) }, +#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DEVELOP) }, +#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) }, + +static Flag flagTable[] = { + VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PRODUCT_FLAG_STRUCT, \ + RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ + RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \ + RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ + RUNTIME_MANAGEABLE_FLAG_STRUCT, \ + RUNTIME_PRODUCT_RW_FLAG_STRUCT, \ + RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) + + RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PRODUCT_FLAG_STRUCT, \ + RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ + RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ + JVMCI_PD_DEVELOP_FLAG_STRUCT, \ + JVMCI_PRODUCT_FLAG_STRUCT, \ + JVMCI_PD_PRODUCT_FLAG_STRUCT, \ + JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ + JVMCI_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // INCLUDE_JVMCI +#ifdef COMPILER1 + C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ + C1_PD_DEVELOP_FLAG_STRUCT, \ + C1_PRODUCT_FLAG_STRUCT, \ + C1_PD_PRODUCT_FLAG_STRUCT, \ + C1_DIAGNOSTIC_FLAG_STRUCT, \ + C1_PD_DIAGNOSTIC_FLAG_STRUCT, \ + C1_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // COMPILER1 +#ifdef COMPILER2 + C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \ + C2_PD_DEVELOP_FLAG_STRUCT, \ + C2_PRODUCT_FLAG_STRUCT, \ + C2_PD_PRODUCT_FLAG_STRUCT, \ + C2_DIAGNOSTIC_FLAG_STRUCT, \ + C2_PD_DIAGNOSTIC_FLAG_STRUCT, \ + C2_EXPERIMENTAL_FLAG_STRUCT, \ + C2_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // COMPILER2 + ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ + ARCH_PRODUCT_FLAG_STRUCT, \ + ARCH_DIAGNOSTIC_FLAG_STRUCT, \ + ARCH_EXPERIMENTAL_FLAG_STRUCT, \ + ARCH_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) + FLAGTABLE_EXT + {0, NULL, NULL} +}; + +Flag* Flag::flags = flagTable; +size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag)); + +inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { + if (s_len != q_len) return false; + return memcmp(s, q, q_len) == 0; +} + +// Search the flag table for a named flag +Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { + for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { + if (str_equal(current->_name, current->get_name_length(), name, length)) { + // Found a matching entry. + // Don't report notproduct and develop flags in product builds. + if (current->is_constant_in_binary()) { + return (return_flag ? current : NULL); + } + // Report locked flags only if allowed. + if (!(current->is_unlocked() || current->is_unlocker())) { + if (!allow_locked) { + // disable use of locked flags, e.g. diagnostic, experimental, + // commercial... until they are explicitly unlocked + return NULL; + } + } + return current; + } + } + // Flag name is not in the flag table + return NULL; +} + +// Get or compute the flag name length +size_t Flag::get_name_length() { + if (_name_len == 0) { + _name_len = strlen(_name); + } + return _name_len; +} + +Flag* Flag::fuzzy_match(const char* name, size_t length, bool allow_locked) { + float VMOptionsFuzzyMatchSimilarity = 0.7f; + Flag* match = NULL; + float score; + float max_score = -1; + + for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { + score = StringUtils::similarity(current->_name, strlen(current->_name), name, length); + if (score > max_score) { + max_score = score; + match = current; + } + } + + if (!(match->is_unlocked() || match->is_unlocker())) { + if (!allow_locked) { + return NULL; + } + } + + if (max_score < VMOptionsFuzzyMatchSimilarity) { + return NULL; + } + + return match; +} + +// Returns the address of the index'th element +static Flag* address_of_flag(CommandLineFlagWithType flag) { + assert((size_t)flag < Flag::numFlags, "bad command line flag index"); + return &Flag::flags[flag]; +} + +bool CommandLineFlagsEx::is_default(CommandLineFlag flag) { + assert((size_t)flag < Flag::numFlags, "bad command line flag index"); + Flag* f = &Flag::flags[flag]; + return f->is_default(); +} + +bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) { + assert((size_t)flag < Flag::numFlags, "bad command line flag index"); + Flag* f = &Flag::flags[flag]; + return f->is_ergonomic(); +} + +bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) { + assert((size_t)flag < Flag::numFlags, "bad command line flag index"); + Flag* f = &Flag::flags[flag]; + return f->is_command_line(); +} + +bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) { + Flag* result = Flag::find_flag((char*)name, strlen(name)); + if (result == NULL) return false; + *value = result->is_command_line(); + return true; +} + +void CommandLineFlagsEx::setOnCmdLine(CommandLineFlagWithType flag) { + Flag* faddr = address_of_flag(flag); + assert(faddr != NULL, "Unknown flag"); + faddr->set_command_line(); +} + +template +static void trace_flag_changed(const char* name, const T old_value, const T new_value, const Flag::Flags origin) { + E e; + e.set_name(name); + e.set_oldValue(old_value); + e.set_newValue(new_value); + e.set_origin(origin); + e.commit(); +} + +static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_bool(new_value, verbose); + } + return status; +} + +Flag::Error CommandLineFlags::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_bool()) return Flag::WRONG_FORMAT; + *value = result->get_bool(); + return Flag::SUCCESS; +} + +Flag::Error CommandLineFlags::boolAtPut(Flag* flag, bool* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_bool()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_bool(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + bool old_value = flag->get_bool(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_bool(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return boolAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); + return CommandLineFlags::boolAtPut(faddr, &value, origin); +} + +static Flag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_int(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_int(new_value, verbose); + } + } + return status; +} + +Flag::Error CommandLineFlags::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_int()) return Flag::WRONG_FORMAT; + *value = result->get_int(); + return Flag::SUCCESS; +} + +Flag::Error CommandLineFlags::intAtPut(Flag* flag, int* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_int()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_int(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + int old_value = flag->get_int(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_int(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return intAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_int(), "wrong flag type"); + return CommandLineFlags::intAtPut(faddr, &value, origin); +} + +static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uint(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uint(new_value, verbose); + } + } + return status; +} + +Flag::Error CommandLineFlags::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_uint()) return Flag::WRONG_FORMAT; + *value = result->get_uint(); + return Flag::SUCCESS; +} + +Flag::Error CommandLineFlags::uintAtPut(Flag* flag, uint* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_uint()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_uint(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + uint old_value = flag->get_uint(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uint(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return uintAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type"); + return CommandLineFlags::uintAtPut(faddr, &value, origin); +} + +Flag::Error CommandLineFlags::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_intx()) return Flag::WRONG_FORMAT; + *value = result->get_intx(); + return Flag::SUCCESS; +} + +static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_intx(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_intx(new_value, verbose); + } + } + return status; +} + +Flag::Error CommandLineFlags::intxAtPut(Flag* flag, intx* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_intx()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_intx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + intx old_value = flag->get_intx(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_intx(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return intxAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); + return CommandLineFlags::intxAtPut(faddr, &value, origin); +} + +Flag::Error CommandLineFlags::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_uintx()) return Flag::WRONG_FORMAT; + *value = result->get_uintx(); + return Flag::SUCCESS; +} + +static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uintx(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uintx(new_value, verbose); + } + } + return status; +} + +Flag::Error CommandLineFlags::uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_uintx()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_uintx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + uintx old_value = flag->get_uintx(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uintx(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return uintxAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); + return CommandLineFlags::uintxAtPut(faddr, &value, origin); +} + +Flag::Error CommandLineFlags::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_uint64_t()) return Flag::WRONG_FORMAT; + *value = result->get_uint64_t(); + return Flag::SUCCESS; +} + +static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uint64_t(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uint64_t(new_value, verbose); + } + } + return status; +} + +Flag::Error CommandLineFlags::uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_uint64_t()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + uint64_t old_value = flag->get_uint64_t(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uint64_t(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return uint64_tAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); + return CommandLineFlags::uint64_tAtPut(faddr, &value, origin); +} + +Flag::Error CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_size_t()) return Flag::WRONG_FORMAT; + *value = result->get_size_t(); + return Flag::SUCCESS; +} + +static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_size_t(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_size_t(new_value, verbose); + } + } + return status; +} + + +Flag::Error CommandLineFlags::size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_size_t()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_size_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + size_t old_value = flag->get_size_t(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_size_t(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return size_tAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); + return CommandLineFlags::size_tAtPut(faddr, &value, origin); +} + +Flag::Error CommandLineFlags::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_double()) return Flag::WRONG_FORMAT; + *value = result->get_double(); + return Flag::SUCCESS; +} + +static Flag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + if (range != NULL) { + status = range->check_double(new_value, verbose); + } + if (status == Flag::SUCCESS) { + CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_double(new_value, verbose); + } + } + return status; +} + +Flag::Error CommandLineFlags::doubleAtPut(Flag* flag, double* value, Flag::Flags origin) { + const char* name; + if (flag == NULL) return Flag::INVALID_FLAG; + if (!flag->is_double()) return Flag::WRONG_FORMAT; + name = flag->_name; + Flag::Error check = apply_constraint_and_check_range_double(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); + if (check != Flag::SUCCESS) return check; + double old_value = flag->get_double(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_double(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + return doubleAtPut(result, value, origin); +} + +Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); + return CommandLineFlags::doubleAtPut(faddr, &value, origin); +} + +Flag::Error CommandLineFlags::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) { + Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_ccstr()) return Flag::WRONG_FORMAT; + *value = result->get_ccstr(); + return Flag::SUCCESS; +} + +Flag::Error CommandLineFlags::ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin) { + Flag* result = Flag::find_flag(name, len); + if (result == NULL) return Flag::INVALID_FLAG; + if (!result->is_ccstr()) return Flag::WRONG_FORMAT; + ccstr old_value = result->get_ccstr(); + trace_flag_changed(name, old_value, *value, origin); + char* new_value = NULL; + if (*value != NULL) { + new_value = os::strdup_check_oom(*value); + } + Flag::Error check = result->set_ccstr(new_value); + if (result->is_default() && old_value != NULL) { + // Prior value is NOT heap allocated, but was a literal constant. + old_value = os::strdup_check_oom(old_value); + } + *value = old_value; + result->set_origin(origin); + return check; +} + +Flag::Error CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); + ccstr old_value = faddr->get_ccstr(); + trace_flag_changed(faddr->_name, old_value, value, origin); + char* new_value = os::strdup_check_oom(value); + Flag::Error check = faddr->set_ccstr(new_value); + if (!faddr->is_default() && old_value != NULL) { + // Prior value is heap allocated so free it. + FREE_C_HEAP_ARRAY(char, old_value); + } + faddr->set_origin(origin); + return check; +} + +extern "C" { + static int compare_flags(const void* void_a, const void* void_b) { + return strcmp((*((Flag**) void_a))->_name, (*((Flag**) void_b))->_name); + } +} + +void CommandLineFlags::printSetFlags(outputStream* out) { + // Print which flags were set on the command line + // note: this method is called before the thread structure is in place + // which means resource allocation cannot be used. + + // The last entry is the null entry. + const size_t length = Flag::numFlags - 1; + + // Sort + Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments); + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; + } + qsort(array, length, sizeof(Flag*), compare_flags); + + // Print + for (size_t i = 0; i < length; i++) { + if (array[i]->get_origin() /* naked field! */) { + array[i]->print_as_flag(out); + out->print(" "); + } + } + out->cr(); + FREE_C_HEAP_ARRAY(Flag*, array); +} + +#ifndef PRODUCT + +void CommandLineFlags::verify() { + assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); +} + +#endif // PRODUCT + +void CommandLineFlags::printFlags(outputStream* out, bool withComments, bool printRanges) { + // Print the flags sorted by name + // note: this method is called before the thread structure is in place + // which means resource allocation cannot be used. + + // The last entry is the null entry. + const size_t length = Flag::numFlags - 1; + + // Sort + Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments); + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; + } + qsort(array, length, sizeof(Flag*), compare_flags); + + // Print + if (!printRanges) { + out->print_cr("[Global flags]"); + } else { + out->print_cr("[Global flags ranges]"); + } + + for (size_t i = 0; i < length; i++) { + if (array[i]->is_unlocked()) { + array[i]->print_on(out, withComments, printRanges); + } + } + FREE_C_HEAP_ARRAY(Flag*, array); +} diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 0344c99a2d8..bdd3c420bc3 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -108,6 +108,349 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); #endif // no compilers +// string type aliases used only in this file +typedef const char* ccstr; +typedef const char* ccstrlist; // represents string arguments which accumulate + +// function type that will construct default range string +typedef const char* (*RangeStrFunc)(void); + +struct Flag { + enum Flags { + // latest value origin + DEFAULT = 0, + COMMAND_LINE = 1, + ENVIRON_VAR = 2, + CONFIG_FILE = 3, + MANAGEMENT = 4, + ERGONOMIC = 5, + ATTACH_ON_DEMAND = 6, + INTERNAL = 7, + + LAST_VALUE_ORIGIN = INTERNAL, + VALUE_ORIGIN_BITS = 4, + VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), + + // flag kind + KIND_PRODUCT = 1 << 4, + KIND_MANAGEABLE = 1 << 5, + KIND_DIAGNOSTIC = 1 << 6, + KIND_EXPERIMENTAL = 1 << 7, + KIND_NOT_PRODUCT = 1 << 8, + KIND_DEVELOP = 1 << 9, + KIND_PLATFORM_DEPENDENT = 1 << 10, + KIND_READ_WRITE = 1 << 11, + KIND_C1 = 1 << 12, + KIND_C2 = 1 << 13, + KIND_ARCH = 1 << 14, + KIND_LP64_PRODUCT = 1 << 15, + KIND_COMMERCIAL = 1 << 16, + KIND_JVMCI = 1 << 17, + + // set this bit if the flag was set on the command line + ORIG_COMMAND_LINE = 1 << 18, + + KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) + }; + + enum Error { + // no error + SUCCESS = 0, + // flag name is missing + MISSING_NAME, + // flag value is missing + MISSING_VALUE, + // error parsing the textual form of the value + WRONG_FORMAT, + // flag is not writable + NON_WRITABLE, + // flag value is outside of its bounds + OUT_OF_BOUNDS, + // flag value violates its constraint + VIOLATES_CONSTRAINT, + // there is no flag with the given name + INVALID_FLAG, + // the flag can only be set only on command line during invocation of the VM + COMMAND_LINE_ONLY, + // the flag may only be set once + SET_ONLY_ONCE, + // the flag is not writable in this combination of product/debug build + CONSTANT, + // other, unspecified error related to setting the flag + ERR_OTHER + }; + + enum MsgType { + NONE = 0, + DIAGNOSTIC_FLAG_BUT_LOCKED, + EXPERIMENTAL_FLAG_BUT_LOCKED, + DEVELOPER_FLAG_BUT_PRODUCT_BUILD, + NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD, + COMMERCIAL_FLAG_BUT_DISABLED, + COMMERCIAL_FLAG_BUT_LOCKED + }; + + const char* _type; + const char* _name; + void* _addr; + NOT_PRODUCT(const char* _doc;) + Flags _flags; + size_t _name_len; + + // points to all Flags static array + static Flag* flags; + + // number of flags + static size_t numFlags; + + static Flag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); }; + static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); + static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); + + static const char* get_int_default_range_str(); + static const char* get_uint_default_range_str(); + static const char* get_intx_default_range_str(); + static const char* get_uintx_default_range_str(); + static const char* get_uint64_t_default_range_str(); + static const char* get_size_t_default_range_str(); + static const char* get_double_default_range_str(); + + Flag::Error check_writable(bool changed); + + bool is_bool() const; + bool get_bool() const; + Flag::Error set_bool(bool value); + + bool is_int() const; + int get_int() const; + Flag::Error set_int(int value); + + bool is_uint() const; + uint get_uint() const; + Flag::Error set_uint(uint value); + + bool is_intx() const; + intx get_intx() const; + Flag::Error set_intx(intx value); + + bool is_uintx() const; + uintx get_uintx() const; + Flag::Error set_uintx(uintx value); + + bool is_uint64_t() const; + uint64_t get_uint64_t() const; + Flag::Error set_uint64_t(uint64_t value); + + bool is_size_t() const; + size_t get_size_t() const; + Flag::Error set_size_t(size_t value); + + bool is_double() const; + double get_double() const; + Flag::Error set_double(double value); + + bool is_ccstr() const; + bool ccstr_accumulates() const; + ccstr get_ccstr() const; + Flag::Error set_ccstr(ccstr value); + + Flags get_origin(); + void set_origin(Flags origin); + + size_t get_name_length(); + + bool is_default(); + bool is_ergonomic(); + bool is_command_line(); + void set_command_line(); + + bool is_product() const; + bool is_manageable() const; + bool is_diagnostic() const; + bool is_experimental() const; + bool is_notproduct() const; + bool is_develop() const; + bool is_read_write() const; + bool is_commercial() const; + + bool is_constant_in_binary() const; + + bool is_unlocker() const; + bool is_unlocked() const; + bool is_writeable() const; + bool is_external() const; + + bool is_unlocker_ext() const; + bool is_unlocked_ext() const; + bool is_writeable_ext() const; + bool is_external_ext() const; + + void clear_diagnostic(); + + Flag::MsgType get_locked_message(char*, int) const; + Flag::MsgType get_locked_message_ext(char*, int) const; + + // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges + void print_on(outputStream* st, bool withComments = false, bool printRanges = false); + void print_kind(outputStream* st, unsigned int width); + void print_origin(outputStream* st, unsigned int width); + void print_as_flag(outputStream* st); + + static const char* flag_error_str(Flag::Error error); +}; + +// debug flags control various aspects of the VM and are global accessible + +// use FlagSetting to temporarily change some debug flag +// e.g. FlagSetting fs(DebugThisAndThat, true); +// restored to previous value upon leaving scope +class FlagSetting { + bool val; + bool* flag; + public: + FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; } + ~FlagSetting() { *flag = val; } +}; + + +class CounterSetting { + intx* counter; + public: + CounterSetting(intx* cnt) { counter = cnt; (*counter)++; } + ~CounterSetting() { (*counter)--; } +}; + +class IntFlagSetting { + int val; + int* flag; + public: + IntFlagSetting(int& fl, int newValue) { flag = &fl; val = fl; fl = newValue; } + ~IntFlagSetting() { *flag = val; } +}; + +class UIntFlagSetting { + uint val; + uint* flag; + public: + UIntFlagSetting(uint& fl, uint newValue) { flag = &fl; val = fl; fl = newValue; } + ~UIntFlagSetting() { *flag = val; } +}; + +class UIntXFlagSetting { + uintx val; + uintx* flag; + public: + UIntXFlagSetting(uintx& fl, uintx newValue) { flag = &fl; val = fl; fl = newValue; } + ~UIntXFlagSetting() { *flag = val; } +}; + +class DoubleFlagSetting { + double val; + double* flag; + public: + DoubleFlagSetting(double& fl, double newValue) { flag = &fl; val = fl; fl = newValue; } + ~DoubleFlagSetting() { *flag = val; } +}; + +class SizeTFlagSetting { + size_t val; + size_t* flag; + public: + SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } + ~SizeTFlagSetting() { *flag = val; } +}; + +// Helper class for temporarily saving the value of a flag during a scope. +template +class FlagGuard { + unsigned char _value[SIZE]; + void* const _addr; + + // Hide operator new, this class should only be allocated on the stack. + // NOTE: Cannot include memory/allocation.hpp here due to circular + // dependencies. + void* operator new(size_t size) throw(); + void* operator new [](size_t size) throw(); + + public: + FlagGuard(void* flag_addr) : _addr(flag_addr) { + memcpy(_value, _addr, SIZE); + } + + ~FlagGuard() { + memcpy(_addr, _value, SIZE); + } +}; + +#define FLAG_GUARD(f) FlagGuard f ## _guard(&f) + +class CommandLineFlags { +public: + static Flag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error boolAtPut(Flag* flag, bool* value, Flag::Flags origin); + static Flag::Error boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin); + static Flag::Error boolAtPut(const char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } + + static Flag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error intAtPut(Flag* flag, int* value, Flag::Flags origin); + static Flag::Error intAtPut(const char* name, size_t len, int* value, Flag::Flags origin); + static Flag::Error intAtPut(const char* name, int* value, Flag::Flags origin) { return intAtPut(name, strlen(name), value, origin); } + + static Flag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error uintAtPut(Flag* flag, uint* value, Flag::Flags origin); + static Flag::Error uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin); + static Flag::Error uintAtPut(const char* name, uint* value, Flag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); } + + static Flag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error intxAtPut(Flag* flag, intx* value, Flag::Flags origin); + static Flag::Error intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin); + static Flag::Error intxAtPut(const char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } + + static Flag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin); + static Flag::Error uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin); + static Flag::Error uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } + + static Flag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin); + static Flag::Error size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin); + static Flag::Error size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } + + static Flag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin); + static Flag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin); + static Flag::Error uint64_tAtPut(const char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } + + static Flag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); } + static Flag::Error doubleAtPut(Flag* flag, double* value, Flag::Flags origin); + static Flag::Error doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin); + static Flag::Error doubleAtPut(const char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } + + static Flag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false); + static Flag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); } + // Contract: Flag will make private copy of the incoming value. + // Outgoing value is always malloc-ed, and caller MUST call free. + static Flag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin); + static Flag::Error ccstrAtPut(const char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } + + // Returns false if name is not a command line flag. + static bool wasSetOnCmdline(const char* name, bool* value); + static void printSetFlags(outputStream* out); + + // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges + static void printFlags(outputStream* out, bool withComments, bool printRanges = false); + + static void verify() PRODUCT_RETURN; +}; + // use this for flags that are true by default in the debug version but // false in the optimized version, and vice versa #ifdef ASSERT @@ -193,10 +536,10 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); // it can be done in the same way as product_rw. // // range is a macro that will expand to min and max arguments for range -// checking code if provided - see jvmFlagRangeList.hpp +// checking code if provided - see commandLineFlagRangeList.hpp // // constraint is a macro that will expand to custom function call -// for constraint checking if provided - see jvmFlagConstraintList.hpp +// for constraint checking if provided - see commandLineFlagConstraintList.hpp // // writeable is a macro that controls if and how the value can change during the runtime // diff --git a/src/hotspot/share/runtime/globals_ext.hpp b/src/hotspot/share/runtime/globals_ext.hpp index b1802493b61..f3d4c992668 100644 --- a/src/hotspot/share/runtime/globals_ext.hpp +++ b/src/hotspot/share/runtime/globals_ext.hpp @@ -27,11 +27,11 @@ // globals_extension.hpp extension -// Additional JVMFlags enum values -#define JVMFLAGS_EXT +// Additional CommandLineFlags enum values +#define COMMANDLINEFLAG_EXT -// Additional JVMFlagsWithType enum values -#define JVMFLAGSWITHTYPE_EXT +// Additional CommandLineFlagsWithType enum values +#define COMMANDLINEFLAGWITHTYPE_EXT // globals.cpp extension @@ -45,26 +45,26 @@ // Default method implementations -inline bool JVMFlag::is_unlocker_ext() const { +inline bool Flag::is_unlocker_ext() const { return false; } -inline bool JVMFlag::is_unlocked_ext() const { +inline bool Flag::is_unlocked_ext() const { return true; } -inline bool JVMFlag::is_writeable_ext() const { +inline bool Flag::is_writeable_ext() const { return false; } -inline bool JVMFlag::is_external_ext() const { +inline bool Flag::is_external_ext() const { return false; } -inline JVMFlag::MsgType JVMFlag::get_locked_message_ext(char* buf, int buflen) const { +inline Flag::MsgType Flag::get_locked_message_ext(char* buf, int buflen) const { assert(buf != NULL, "Buffer cannot be NULL"); buf[0] = '\0'; - return JVMFlag::NONE; + return Flag::NONE; } #endif // SHARE_VM_RUNTIME_GLOBALS_EXT_HPP diff --git a/src/hotspot/share/runtime/globals_extension.hpp b/src/hotspot/share/runtime/globals_extension.hpp index 0297b3d08db..38c8701715f 100644 --- a/src/hotspot/share/runtime/globals_extension.hpp +++ b/src/hotspot/share/runtime/globals_extension.hpp @@ -27,6 +27,7 @@ #include "runtime/globals.hpp" #include "utilities/macros.hpp" +#include "utilities/macros.hpp" #if INCLUDE_JVMCI #include "jvmci/jvmci_globals.hpp" #endif @@ -163,9 +164,9 @@ typedef enum { IGNORE_RANGE, \ IGNORE_CONSTRAINT, \ IGNORE_WRITEABLE) - JVMFLAGS_EXT - NUM_JVMFlags -} JVMFlags; + COMMANDLINEFLAG_EXT + NUM_CommandLineFlag +} CommandLineFlag; // Construct enum of Flag__ constants. @@ -292,19 +293,19 @@ typedef enum { IGNORE_RANGE, IGNORE_CONSTRAINT, IGNORE_WRITEABLE) - JVMFLAGSWITHTYPE_EXT - NUM_JVMFlagsWithType -} JVMFlagsWithType; + COMMANDLINEFLAGWITHTYPE_EXT + NUM_CommandLineFlagWithType +} CommandLineFlagWithType; -#define FLAG_IS_DEFAULT(name) (JVMFlagEx::is_default(FLAG_MEMBER(name))) -#define FLAG_IS_ERGO(name) (JVMFlagEx::is_ergo(FLAG_MEMBER(name))) -#define FLAG_IS_CMDLINE(name) (JVMFlagEx::is_cmdline(FLAG_MEMBER(name))) +#define FLAG_IS_DEFAULT(name) (CommandLineFlagsEx::is_default(FLAG_MEMBER(name))) +#define FLAG_IS_ERGO(name) (CommandLineFlagsEx::is_ergo(FLAG_MEMBER(name))) +#define FLAG_IS_CMDLINE(name) (CommandLineFlagsEx::is_cmdline(FLAG_MEMBER(name))) #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) -#define FLAG_SET_CMDLINE(type, name, value) (JVMFlagEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \ - JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::COMMAND_LINE)) -#define FLAG_SET_ERGO(type, name, value) (JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::ERGONOMIC)) +#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \ + CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), Flag::COMMAND_LINE)) +#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), Flag::ERGONOMIC)) #define FLAG_SET_ERGO_IF_DEFAULT(type, name, value) \ do { \ if (FLAG_IS_DEFAULT(name)) { \ @@ -312,26 +313,26 @@ typedef enum { } \ } while (0) -// Can't put the following in JVMFlags because +// Can't put the following in CommandLineFlags because // of a circular dependency on the enum definition. -class JVMFlagEx : JVMFlag { +class CommandLineFlagsEx : CommandLineFlags { public: - static JVMFlag::Error boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin); - static JVMFlag::Error intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin); - static JVMFlag::Error uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin); - static JVMFlag::Error intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin); - static JVMFlag::Error uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin); - static JVMFlag::Error uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin); - static JVMFlag::Error size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin); - static JVMFlag::Error doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin); + static Flag::Error boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin); + static Flag::Error intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin); + static Flag::Error uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin); + static Flag::Error intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin); + static Flag::Error uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin); + static Flag::Error uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin); + static Flag::Error size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin); + static Flag::Error doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin); // Contract: Flag will make private copy of the incoming value - static JVMFlag::Error ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin); + static Flag::Error ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin); - static bool is_default(JVMFlags flag); - static bool is_ergo(JVMFlags flag); - static bool is_cmdline(JVMFlags flag); + static bool is_default(CommandLineFlag flag); + static bool is_ergo(CommandLineFlag flag); + static bool is_cmdline(CommandLineFlag flag); - static void setOnCmdLine(JVMFlagsWithType flag); + static void setOnCmdLine(CommandLineFlagWithType flag); }; #endif // SHARE_VM_RUNTIME_GLOBALS_EXTENSION_HPP diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index 7836e558888..a903eef7c39 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -26,7 +26,6 @@ #define SHARE_VM_RUNTIME_HANDSHAKE_HPP #include "memory/allocation.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/semaphore.hpp" class ThreadClosure; diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 6c4d000267f..944ddeb83a9 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -30,7 +30,7 @@ #include "interpreter/bytecodes.hpp" #include "memory/universe.hpp" #include "prims/methodHandles.hpp" -#include "runtime/flags/jvmFlag.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" #include "runtime/init.hpp" @@ -155,7 +155,7 @@ jint init_globals() { // All the flags that get adjusted by VM_Version_init and os::init_2 // have been set so dump the flags now. if (PrintFlagsFinal || PrintFlagsRanges) { - JVMFlag::printFlags(tty, false, PrintFlagsRanges); + CommandLineFlags::printFlags(tty, false, PrintFlagsRanges); } return JNI_OK; diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index fd17e47a48e..c1c8a3d1bca 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -54,7 +54,6 @@ #include "runtime/biasedLocking.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index e94dcd0286e..7a0cd44c099 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -26,7 +26,6 @@ #define SHARE_VM_RUNTIME_MUTEXLOCKER_HPP #include "memory/allocation.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/mutex.hpp" // Mutexes used in the VM. diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index ff9a38a3d45..b70e3025039 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -63,11 +63,12 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/flags/jvmFlagConstraintList.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" -#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/commandLineFlagWriteableList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/globals.hpp" #include "runtime/handshake.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -3662,17 +3663,17 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { if (ergo_result != JNI_OK) return ergo_result; // Final check of all ranges after ergonomics which may change values. - if (!JVMFlagRangeList::check_ranges()) { + if (!CommandLineFlagRangeList::check_ranges()) { return JNI_EINVAL; } // Final check of all 'AfterErgo' constraints after ergonomics which may change values. - bool constraint_result = JVMFlagConstraintList::check_constraints(JVMFlagConstraint::AfterErgo); + bool constraint_result = CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterErgo); if (!constraint_result) { return JNI_EINVAL; } - JVMFlagWriteableList::mark_startup(); + CommandLineFlagWriteableList::mark_startup(); if (PauseAtStartup) { os::pause(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index ccce40e837e..8ad9b2a6e5d 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -82,7 +82,6 @@ #include "prims/jvmtiAgentThread.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" @@ -718,7 +717,7 @@ typedef PaddedEnd PaddedObjectMonitor; nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ - nonstatic_field(nmethod, _state, volatile signed char) \ + nonstatic_field(nmethod, _state, volatile signed char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ @@ -1060,12 +1059,12 @@ typedef PaddedEnd PaddedObjectMonitor; /* -XX flags */ \ /*********************/ \ \ - nonstatic_field(JVMFlag, _type, const char*) \ - nonstatic_field(JVMFlag, _name, const char*) \ - unchecked_nonstatic_field(JVMFlag, _addr, sizeof(void*)) /* NOTE: no type */ \ - nonstatic_field(JVMFlag, _flags, JVMFlag::Flags) \ - static_field(JVMFlag, flags, JVMFlag*) \ - static_field(JVMFlag, numFlags, size_t) \ + nonstatic_field(Flag, _type, const char*) \ + nonstatic_field(Flag, _name, const char*) \ + unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) /* NOTE: no type */ \ + nonstatic_field(Flag, _flags, Flag::Flags) \ + static_field(Flag, flags, Flag*) \ + static_field(Flag, numFlags, size_t) \ \ /*************************/ \ /* JDK / VM version info */ \ @@ -1432,18 +1431,18 @@ typedef PaddedEnd PaddedObjectMonitor; declare_toplevel_type(SharedRuntime) \ \ declare_toplevel_type(CodeBlob) \ - declare_type(RuntimeBlob, CodeBlob) \ - declare_type(BufferBlob, RuntimeBlob) \ + declare_type(RuntimeBlob, CodeBlob) \ + declare_type(BufferBlob, RuntimeBlob) \ declare_type(AdapterBlob, BufferBlob) \ declare_type(MethodHandlesAdapterBlob, BufferBlob) \ declare_type(CompiledMethod, CodeBlob) \ declare_type(nmethod, CompiledMethod) \ - declare_type(RuntimeStub, RuntimeBlob) \ - declare_type(SingletonBlob, RuntimeBlob) \ + declare_type(RuntimeStub, RuntimeBlob) \ + declare_type(SingletonBlob, RuntimeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ - declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ + declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -1897,8 +1896,8 @@ typedef PaddedEnd PaddedObjectMonitor; /* -XX flags */ \ /********************/ \ \ - declare_toplevel_type(JVMFlag) \ - declare_toplevel_type(JVMFlag*) \ + declare_toplevel_type(Flag) \ + declare_toplevel_type(Flag*) \ \ /********************/ \ /* JVMTI */ \ @@ -1938,7 +1937,7 @@ typedef PaddedEnd PaddedObjectMonitor; declare_integer_type(ThreadState) \ declare_integer_type(Location::Type) \ declare_integer_type(Location::Where) \ - declare_integer_type(JVMFlag::Flags) \ + declare_integer_type(Flag::Flags) \ COMPILER2_PRESENT(declare_integer_type(OptoReg::Name)) \ \ declare_toplevel_type(CHeapObj) \ diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index 8264727e086..ff4705cb8f6 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -31,7 +31,6 @@ #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -276,9 +275,9 @@ static jint set_flag(AttachOperation* op, outputStream* out) { FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); - if (ret != JVMFlag::SUCCESS) { - if (ret == JVMFlag::NON_WRITABLE) { + int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), Flag::ATTACH_ON_DEMAND, err_msg); + if (ret != Flag::SUCCESS) { + if (ret == Flag::NON_WRITABLE) { // if the flag is not manageable try to change it through // the platform dependent implementation return AttachListener::pd_set_flag(op, out); @@ -299,7 +298,7 @@ static jint print_flag(AttachOperation* op, outputStream* out) { out->print_cr("flag name is missing"); return JNI_ERR; } - JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name)); + Flag* f = Flag::find_flag((char*)name, strlen(name)); if (f) { f->print_as_flag(out); out->cr(); diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 0c5388168a8..ce7de97dffa 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -33,7 +33,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" -#include "runtime/flags/jvmFlag.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" @@ -231,9 +231,9 @@ PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) : void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) { if (_all.value()) { - JVMFlag::printFlags(output(), true); + CommandLineFlags::printFlags(output(), true); } else { - JVMFlag::printSetFlags(output()); + CommandLineFlags::printSetFlags(output()); } } @@ -264,9 +264,9 @@ void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) { } FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlag::MANAGEMENT, err_msg); + int ret = WriteableFlags::set_flag(_flag.value(), val, Flag::MANAGEMENT, err_msg); - if (ret != JVMFlag::SUCCESS) { + if (ret != Flag::SUCCESS) { output()->print_cr("%s", err_msg.buffer()); } } diff --git a/src/hotspot/share/services/dtraceAttacher.cpp b/src/hotspot/share/services/dtraceAttacher.cpp index 2d7e32c2ddc..d923bc1282e 100644 --- a/src/hotspot/share/services/dtraceAttacher.cpp +++ b/src/hotspot/share/services/dtraceAttacher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "code/codeCache.hpp" #include "memory/resourceArea.hpp" #include "runtime/deoptimization.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/dtraceAttacher.hpp" @@ -51,8 +50,8 @@ class VM_DeoptimizeTheWorld : public VM_Operation { }; static void set_bool_flag(const char* flag, bool value) { - JVMFlag::boolAtPut((char*)flag, strlen(flag), &value, - JVMFlag::ATTACH_ON_DEMAND); + CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value, + Flag::ATTACH_ON_DEMAND); } // Enable only the "fine grained" flags. Do *not* touch diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index ec44089c18f..a75ae1a6a43 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -36,7 +36,6 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -867,10 +866,10 @@ static jint get_vm_thread_count() { static jint get_num_flags() { // last flag entry is always NULL, so subtract 1 - int nFlags = (int) JVMFlag::numFlags - 1; + int nFlags = (int) Flag::numFlags - 1; int count = 0; for (int i = 0; i < nFlags; i++) { - JVMFlag* flag = &JVMFlag::flags[i]; + Flag* flag = &Flag::flags[i]; // Exclude the locked (diagnostic, experimental) flags if (flag->is_unlocked() || flag->is_unlocker()) { count++; @@ -1420,14 +1419,14 @@ JVM_END // Returns a String array of all VM global flag names JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env)) // last flag entry is always NULL, so subtract 1 - int nFlags = (int) JVMFlag::numFlags - 1; + int nFlags = (int) Flag::numFlags - 1; // allocate a temp array objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), nFlags, CHECK_0); objArrayHandle flags_ah(THREAD, r); int num_entries = 0; for (int i = 0; i < nFlags; i++) { - JVMFlag* flag = &JVMFlag::flags[i]; + Flag* flag = &Flag::flags[i]; // Exclude notproduct and develop flags in product builds. if (flag->is_constant_in_binary()) { continue; @@ -1455,7 +1454,7 @@ JVM_END // Utility function used by jmm_GetVMGlobals. Returns false if flag type // can't be determined, true otherwise. If false is returned, then *global // will be incomplete and invalid. -bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, JVMFlag *flag, TRAPS) { +bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { Handle flag_name; if (name() == NULL) { flag_name = java_lang_String::create_from_str(flag->_name, CHECK_false); @@ -1500,25 +1499,25 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, JVMFlag *fl global->writeable = flag->is_writeable(); global->external = flag->is_external(); switch (flag->get_origin()) { - case JVMFlag::DEFAULT: + case Flag::DEFAULT: global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT; break; - case JVMFlag::COMMAND_LINE: + case Flag::COMMAND_LINE: global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE; break; - case JVMFlag::ENVIRON_VAR: + case Flag::ENVIRON_VAR: global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR; break; - case JVMFlag::CONFIG_FILE: + case Flag::CONFIG_FILE: global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE; break; - case JVMFlag::MANAGEMENT: + case Flag::MANAGEMENT: global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT; break; - case JVMFlag::ERGONOMIC: + case Flag::ERGONOMIC: global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC; break; - case JVMFlag::ATTACH_ON_DEMAND: + case Flag::ATTACH_ON_DEMAND: global->origin = JMM_VMGLOBAL_ORIGIN_ATTACH_ON_DEMAND; break; default: @@ -1532,7 +1531,7 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, JVMFlag *fl // specified by names. If names == NULL, fill globals array // with all Flags. Return value is number of entries // created in globals. -// If a JVMFlag with a given name in an array element does not +// If a Flag with a given name in an array element does not // exist, globals[i].name will be set to NULL. JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, jobjectArray names, @@ -1567,7 +1566,7 @@ JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, Handle sh(THREAD, s); char* str = java_lang_String::as_utf8_string(s); - JVMFlag* flag = JVMFlag::find_flag(str, strlen(str)); + Flag* flag = Flag::find_flag(str, strlen(str)); if (flag != NULL && add_global_entry(env, sh, &globals[i], flag, THREAD)) { num_entries++; @@ -1580,11 +1579,11 @@ JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, // return all globals if names == NULL // last flag entry is always NULL, so subtract 1 - int nFlags = (int) JVMFlag::numFlags - 1; + int nFlags = (int) Flag::numFlags - 1; Handle null_h; int num_entries = 0; for (int i = 0; i < nFlags && num_entries < count; i++) { - JVMFlag* flag = &JVMFlag::flags[i]; + Flag* flag = &Flag::flags[i]; // Exclude notproduct and develop flags in product builds. if (flag->is_constant_in_binary()) { continue; @@ -1610,10 +1609,10 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value char* name = java_lang_String::as_utf8_string(fn); FormatBuffer<80> error_msg("%s", ""); - int succeed = WriteableFlags::set_flag(name, new_value, JVMFlag::MANAGEMENT, error_msg); + int succeed = WriteableFlags::set_flag(name, new_value, Flag::MANAGEMENT, error_msg); - if (succeed != JVMFlag::SUCCESS) { - if (succeed == JVMFlag::MISSING_VALUE) { + if (succeed != Flag::SUCCESS) { + if (succeed == Flag::MISSING_VALUE) { // missing value causes NPE to be thrown THROW(vmSymbols::java_lang_NullPointerException()); } else { @@ -1622,7 +1621,7 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value error_msg.buffer()); } } - assert(succeed == JVMFlag::SUCCESS, "Setting flag should succeed"); + assert(succeed == Flag::SUCCESS, "Setting flag should succeed"); JVM_END class ThreadTimesClosure: public ThreadClosure { diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp index fee4e68b51f..54b59635c2e 100644 --- a/src/hotspot/share/services/writeableFlags.cpp +++ b/src/hotspot/share/services/writeableFlags.cpp @@ -26,8 +26,7 @@ #include "classfile/javaClasses.hpp" #include "memory/allocation.inline.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/commandLineFlagRangeList.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" #include "services/writeableFlags.hpp" @@ -39,7 +38,7 @@ static void buffer_concat(char* buffer, const char* src) { } static void print_flag_error_message_bounds(const char* name, char* buffer) { - JVMFlagRange* range = JVMFlagRangeList::find(name); + CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); if (range != NULL) { buffer_concat(buffer, "must have value in range "); @@ -59,34 +58,34 @@ static void print_flag_error_message_bounds(const char* name, char* buffer) { } } -static void print_flag_error_message_if_needed(JVMFlag::Error error, const char* name, FormatBuffer<80>& err_msg) { - if (error == JVMFlag::SUCCESS) { +static void print_flag_error_message_if_needed(Flag::Error error, const char* name, FormatBuffer<80>& err_msg) { + if (error == Flag::SUCCESS) { return; } char buffer[TEMP_BUF_SIZE] = {'\0'}; - if ((error != JVMFlag::MISSING_NAME) && (name != NULL)) { + if ((error != Flag::MISSING_NAME) && (name != NULL)) { buffer_concat(buffer, name); buffer_concat(buffer, " error: "); } else { buffer_concat(buffer, "Error: "); } switch (error) { - case JVMFlag::MISSING_NAME: + case Flag::MISSING_NAME: buffer_concat(buffer, "flag name is missing."); break; - case JVMFlag::MISSING_VALUE: + case Flag::MISSING_VALUE: buffer_concat(buffer, "parsing the textual form of the value."); break; - case JVMFlag::NON_WRITABLE: + case Flag::NON_WRITABLE: buffer_concat(buffer, "flag is not writeable."); break; - case JVMFlag::OUT_OF_BOUNDS: + case Flag::OUT_OF_BOUNDS: print_flag_error_message_bounds(name, buffer); break; - case JVMFlag::VIOLATES_CONSTRAINT: + case Flag::VIOLATES_CONSTRAINT: buffer_concat(buffer, "value violates its flag's constraint."); break; - case JVMFlag::INVALID_FLAG: + case Flag::INVALID_FLAG: buffer_concat(buffer, "there is no flag with the given name."); break; - case JVMFlag::ERR_OTHER: + case Flag::ERR_OTHER: buffer_concat(buffer, "other, unspecified error related to setting the flag."); break; - case JVMFlag::SUCCESS: + case Flag::SUCCESS: break; default: break; @@ -96,127 +95,127 @@ static void print_flag_error_message_if_needed(JVMFlag::Error error, const char* } // set a boolean global flag -JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { if ((strcasecmp(arg, "true") == 0) || (*arg == '1' && *(arg + 1) == 0)) { return set_bool_flag(name, true, origin, err_msg); } else if ((strcasecmp(arg, "false") == 0) || (*arg == '0' && *(arg + 1) == 0)) { return set_bool_flag(name, false, origin, err_msg); } err_msg.print("flag value must be a boolean (1/0 or true/false)"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::boolAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::boolAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a int global flag -JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { int value; if (sscanf(arg, "%d", &value)) { return set_int_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an integer"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::intAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::intAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uint global flag -JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { uint value; if (sscanf(arg, "%u", &value)) { return set_uint_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::uintAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::uintAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a intx global flag -JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { intx value; if (sscanf(arg, INTX_FORMAT, &value)) { return set_intx_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an integer"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::intxAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::intxAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uintx global flag -JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { uintx value; if (sscanf(arg, UINTX_FORMAT, &value)) { return set_uintx_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::uintxAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::uintxAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uint64_t global flag -JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { uint64_t value; if (sscanf(arg, UINT64_FORMAT, &value)) { return set_uint64_t_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned 64-bit integer"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::uint64_tAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::uint64_tAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a size_t global flag -JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { size_t value; if (sscanf(arg, SIZE_FORMAT, &value)) { return set_size_t_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return JVMFlag::WRONG_FORMAT; + return Flag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::size_tAtPut(name, &value, origin); +Flag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::size_tAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a string global flag using value from AttachOperation -JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { - JVMFlag::Error err = JVMFlag::ccstrAtPut((char*)name, &value, origin); +Flag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { + Flag::Error err = CommandLineFlags::ccstrAtPut((char*)name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } @@ -226,7 +225,7 @@ JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* valu * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg); } @@ -235,42 +234,42 @@ JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_ * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg); } // a writeable flag setter accepting either 'jvalue' or 'char *' values -JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlag::Flags,FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*,const void*,Flag::Flags,FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg) { if (name == NULL) { err_msg.print("flag name is missing"); - return JVMFlag::MISSING_NAME; + return Flag::MISSING_NAME; } if (value == NULL) { err_msg.print("flag value is missing"); - return JVMFlag::MISSING_VALUE; + return Flag::MISSING_VALUE; } - JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name)); + Flag* f = Flag::find_flag((char*)name, strlen(name)); if (f) { // only writeable flags are allowed to be set if (f->is_writeable()) { return setter(f, value, origin, err_msg); } else { err_msg.print("only 'writeable' flags can be set"); - return JVMFlag::NON_WRITABLE; + return Flag::NON_WRITABLE; } } err_msg.print("flag %s does not exist", name); - return JVMFlag::INVALID_FLAG; + return Flag::INVALID_FLAG; } // a writeable flag setter accepting 'char *' values -JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { char* flag_value = *(char**)value; if (flag_value == NULL) { err_msg.print("flag value is missing"); - return JVMFlag::MISSING_VALUE; + return Flag::MISSING_VALUE; } if (f->is_bool()) { return set_bool_flag(f->_name, flag_value, origin, err_msg); @@ -291,11 +290,11 @@ JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, } else { ShouldNotReachHere(); } - return JVMFlag::ERR_OTHER; + return Flag::ERR_OTHER; } // a writeable flag setter accepting 'jvalue' values -JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, +Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { jvalue new_value = *(jvalue*)value; if (f->is_bool()) { @@ -323,16 +322,16 @@ JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* valu oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { err_msg.print("flag value is missing"); - return JVMFlag::MISSING_VALUE; + return Flag::MISSING_VALUE; } ccstr svalue = java_lang_String::as_utf8_string(str); - JVMFlag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg); - if (ret != JVMFlag::SUCCESS) { + Flag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg); + if (ret != Flag::SUCCESS) { FREE_C_HEAP_ARRAY(char, svalue); } return ret; } else { ShouldNotReachHere(); } - return JVMFlag::ERR_OTHER; + return Flag::ERR_OTHER; } diff --git a/src/hotspot/share/services/writeableFlags.hpp b/src/hotspot/share/services/writeableFlags.hpp index 31065982c4c..caa6e0a4757 100644 --- a/src/hotspot/share/services/writeableFlags.hpp +++ b/src/hotspot/share/services/writeableFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,49 +25,48 @@ #ifndef SHARE_VM_SERVICES_WRITEABLEFLAG_HPP #define SHARE_VM_SERVICES_WRITEABLEFLAG_HPP -#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "utilities/formatBuffer.hpp" class WriteableFlags : AllStatic { private: // a writeable flag setter accepting either 'jvalue' or 'char *' values - static JVMFlag::Error set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*, const void*, JVMFlag::Flags, FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*, const void*, Flag::Flags, FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'char *' values - static JVMFlag::Error set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'jvalue' values - static JVMFlag::Error set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static JVMFlag::Error set_bool_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_bool_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a int global flag - static JVMFlag::Error set_int_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_int_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a uint global flag - static JVMFlag::Error set_uint_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_uint_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a intx global flag - static JVMFlag::Error set_intx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_intx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static JVMFlag::Error set_uintx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_uintx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static JVMFlag::Error set_uint64_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_uint64_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static JVMFlag::Error set_size_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_size_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static JVMFlag::Error set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a int global flag - static JVMFlag::Error set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a uint global flag - static JVMFlag::Error set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a intx global flag - static JVMFlag::Error set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static JVMFlag::Error set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static JVMFlag::Error set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static JVMFlag::Error set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg); // set a string global flag - static JVMFlag::Error set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); public: /* sets a writeable flag to the provided value @@ -75,14 +74,14 @@ public: * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static JVMFlag::Error set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg); /* sets a writeable flag to the provided value * * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static JVMFlag::Error set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static Flag::Error set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg); }; #endif /* SHARE_VM_SERVICES_WRITEABLEFLAG_HPP */ diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 1fa5d655058..71bbe5709e2 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -40,7 +40,6 @@ #include "prims/privilegedStack.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 91772d15eba..a6b9fdef58c 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1259,11 +1259,4 @@ static inline void* dereference_vptr(const void* addr) { return *(void**)addr; } -//---------------------------------------------------------------------------------------------------- -// String type aliases used by command line flag declarations and -// processing utilities. - -typedef const char* ccstr; -typedef const char* ccstrlist; // represents string arguments which accumulate - #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_HPP diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index a89820857ac..fe180f189e2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,7 +136,7 @@ public class VM { private Boolean compressedOopsEnabled; private Boolean compressedKlassPointersEnabled; - // command line flags supplied to VM - see struct JVMFlag in jvmFlag.hpp + // command line flags supplied to VM - see struct Flag in globals.hpp public static final class Flag { private String type; private String name; @@ -905,7 +905,7 @@ public class VM { private void readCommandLineFlags() { // get command line flags TypeDataBase db = getTypeDataBase(); - Type flagType = db.lookupType("JVMFlag"); + Type flagType = db.lookupType("Flag"); int numFlags = (int) flagType.getCIntegerField("numFlags").getValue(); // NOTE: last flag contains null values. commandLineFlags = new Flag[numFlags - 1]; diff --git a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp index ce50b73a690..5fd493fa802 100644 --- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp +++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ #include "precompiled.hpp" #include "gc/shared/collectorPolicy.hpp" #include "runtime/arguments.hpp" -#include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/test/hotspot/gtest/runtime/test_globals.cpp b/test/hotspot/gtest/runtime/test_globals.cpp index d2d3ed262af..3a84f2ce714 100644 --- a/test/hotspot/gtest/runtime/test_globals.cpp +++ b/test/hotspot/gtest/runtime/test_globals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,18 +23,17 @@ #include "precompiled.hpp" #include "runtime/globals.hpp" -#include "runtime/flags/flagSetting.hpp" #include "unittest.hpp" -#define TEST_FLAG(f, type, value) \ - do { \ - ASSERT_TRUE(JVMFlag::find_flag(#f)->is_ ## type()); \ - type original_value = f; \ - { \ - FLAG_GUARD(f); \ - f = value; \ - } \ - ASSERT_EQ(original_value, f); \ +#define TEST_FLAG(f, type, value) \ + do { \ + ASSERT_TRUE(Flag::find_flag(#f)->is_ ## type()); \ + type original_value = f; \ + { \ + FLAG_GUARD(f); \ + f = value; \ + } \ + ASSERT_EQ(original_value, f); \ } while (0) TEST_VM(FlagGuard, bool_flag) { From a99eca12cc0410955a0c427ca34baf8991d7dd5a Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 23 Apr 2018 16:00:56 -0400 Subject: [PATCH 020/102] 8201826: G1: Don't invoke WeakProcessor if mark stack has overflowed Move WeakProcessor invocation after overflow check Reviewed-by: stefank, tschatzl --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index d1703a0caf4..b047e00add4 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1695,14 +1695,6 @@ void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) { assert(!rp->discovery_enabled(), "Post condition"); } - assert(has_overflown() || _global_mark_stack.is_empty(), - "Mark stack should be empty (unless it has overflown)"); - - { - GCTraceTime(Debug, gc, phases) debug("Weak Processing", _gc_timer_cm); - WeakProcessor::weak_oops_do(&g1_is_alive, &do_nothing_cl); - } - if (has_overflown()) { // We can not trust g1_is_alive if the marking stack overflowed return; @@ -1710,6 +1702,11 @@ void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) { assert(_global_mark_stack.is_empty(), "Marking should have completed"); + { + GCTraceTime(Debug, gc, phases) debug("Weak Processing", _gc_timer_cm); + WeakProcessor::weak_oops_do(&g1_is_alive, &do_nothing_cl); + } + // Unload Klasses, String, Symbols, Code Cache, etc. if (ClassUnloadingWithConcurrentMark) { GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm); From caf3f257fe24e0724d62c44aa10c99e50c5f8f8e Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 23 Apr 2018 15:19:46 -0700 Subject: [PATCH 021/102] 8202155: quarantine test com/sun/jdi/JdbExprTest.sh on all platforms Quarantined test Reviewed-by: dholmes --- test/jdk/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 19cce551302..d8237287ac4 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -738,6 +738,8 @@ tools/jimage/JImageListTest.java 8198405 windows- com/sun/jdi/RedefineImplementor.sh 8004127 generic-all +com/sun/jdi/JdbExprTest.sh 8185803 generic-all + com/sun/jdi/JdbMethodExitTest.sh 8171483 generic-all com/sun/jdi/RepStep.java 8043571 generic-all From 48d51992ee5e47f3bef12a5d9f5a0d263ac2fc4c Mon Sep 17 00:00:00 2001 From: Lutz Schmidt Date: Mon, 23 Apr 2018 16:10:32 -0700 Subject: [PATCH 022/102] 8202070: Cleanup code after JDK-8200450, JDK-8200366 Reviewed-by: kvn --- src/hotspot/share/code/codeHeapState.cpp | 126 ++++------------------- 1 file changed, 21 insertions(+), 105 deletions(-) diff --git a/src/hotspot/share/code/codeHeapState.cpp b/src/hotspot/share/code/codeHeapState.cpp index e1446aa62b2..2cfe15483b1 100644 --- a/src/hotspot/share/code/codeHeapState.cpp +++ b/src/hotspot/share/code/codeHeapState.cpp @@ -2050,16 +2050,10 @@ void CodeHeapState::print_age(outputStream* out, CodeHeap* heap) { } -#define JDK8200450_REMEDY -#define JDK8200450_TRACE void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { if (!initialization_complete) { return; } -#ifdef JDK8200450_TRACE - out->print_cr("print_names() entered for heap @ " INTPTR_FORMAT, p2i(heap)); - out->flush(); -#endif const char* heapName = get_heapName(heap); get_HeapStatGlobals(out, heapName); @@ -2105,41 +2099,18 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { // Only check granule if it contains at least one blob. unsigned int nBlobs = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count + StatArray[ix].stub_count + StatArray[ix].dead_count; -#ifdef JDK8200450_REMEDY - if (nBlobs > 0 ) -#endif - { + if (nBlobs > 0 ) { for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) { // heap->find_start() is safe. Only working with _segmap. Returns NULL or void*. Returned CodeBlob may be uninitialized. CodeBlob* this_blob = (CodeBlob *)(heap->find_start(low_bound+ix*granule_size+is)); -#ifndef JDK8200450_REMEDY - bool blob_initialized = (this_blob != NULL) -#else -#ifndef JDK8200450_TRACE bool blob_initialized = (this_blob != NULL) && (this_blob->header_size() >= 0) && (this_blob->relocation_size() >= 0) && ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) && - ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin()) && - is_readable_pointer((address)(this_blob->relocation_begin()) && + ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) && + is_readable_pointer((address)(this_blob->relocation_begin())) && is_readable_pointer(this_blob->content_begin()); -#else - int hdr_size = 0; - int reloc_size = 0; - address reloc_begin = NULL; - address cntnt_begin = NULL; - if (this_blob != NULL) { - hdr_size = this_blob->header_size(); - reloc_size = this_blob->relocation_size(); - reloc_begin = (address)(this_blob->relocation_begin()); - cntnt_begin = this_blob->content_begin(); - } - bool blob_initialized = (this_blob != NULL) && (hdr_size >= 0) && (reloc_size >= 0) && - ((address)this_blob + hdr_size == reloc_begin) && - ((address)this_blob + CodeBlob::align_code_offset(hdr_size + reloc_size) == cntnt_begin) && - is_readable_pointer(reloc_begin) && - is_readable_pointer(cntnt_begin); -#endif -#endif - if (blob_initialized && (this_blob != last_blob)) { + // blob could have been flushed, freed, and merged. + // this_blob < last_blob is an indicator for that. + if (blob_initialized && (this_blob > last_blob)) { last_blob = this_blob; //---< get type and name >--- @@ -2147,15 +2118,13 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { if (segment_granules) { cbType = (blobType)StatArray[ix].type; } else { - cbType = get_cbType(this_blob); // Is this here safe? + cbType = get_cbType(this_blob); } - // this_blob->name() could return NULL if no name is given to CTOR. Inlined, maybe invisible on stack + // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack const char* blob_name = this_blob->name(); -#ifdef JDK8200450_REMEDY - if (blob_name == NULL) { + if ((blob_name == NULL) || !is_readable_pointer(blob_name)) { blob_name = ""; } -#endif //---< print table header for new print range >--- if (!name_in_addr_range) { @@ -2174,24 +2143,16 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); ast->fill_to(33); -#ifdef JDK8200450_TRACE - STRINGSTREAM_FLUSH_LOCKED("") // Remove before push!!! -#endif - // this_blob->as_nmethod_or_null() is safe. Inlined, maybe invisible on stack. nmethod* nm = this_blob->as_nmethod_or_null(); Method* method = (nm == NULL) ? NULL : nm->method(); // may be uninitialized, i.e. != NULL, but invalid -#ifdef JDK8200450_REMEDY - if ((nm != NULL) && (method != NULL) && is_readable_pointer(method) && is_readable_pointer(method->constants())) { -#else - if ((nm != NULL) && (method != NULL)) { -#endif + if ((nm != NULL) && (method != NULL) && (cbType != nMethod_dead) && + is_readable_pointer(method) && is_readable_pointer(method->constants())) { ResourceMark rm; //---< collect all data to locals as quickly as possible >--- unsigned int total_size = nm->total_size(); int hotness = nm->hotness_counter(); - bool nm_zombie = nm->is_zombie(); - bool get_name = nm->is_in_use() || nm->is_not_entrant(); + bool get_name = (cbType == nMethod_inuse) || (cbType == nMethod_notused); //---< nMethod size in hex >--- ast->print(PTR32_FORMAT, total_size); ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K); @@ -2205,16 +2166,11 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { ast->fill_to(62+6); ast->print("%s", blobTypeName[cbType]); ast->fill_to(82+6); - if (nm_zombie) { + if (cbType == nMethod_dead) { ast->print("%14s", " zombie method"); } -#ifdef JDK8200450_TRACE - STRINGSTREAM_FLUSH_LOCKED("") // Remove before push!!! -#endif - if (get_name) { -#ifdef JDK8200450_REMEDY Symbol* methName = method->name(); const char* methNameS = (methName == NULL) ? NULL : methName->as_C_string(); methNameS = (methNameS == NULL) ? "" : methNameS; @@ -2223,10 +2179,6 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { methSigS = (methSigS == NULL) ? "" : methSigS; ast->print("%s", methNameS); ast->print("%s", methSigS); -#else - blob_name = method->name_and_sig_as_C_string(); - ast->print("%s", blob_name); -#endif } else { ast->print("%s", blob_name); } @@ -2237,45 +2189,9 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { ast->print("%s", blob_name); } STRINGSTREAM_FLUSH_LOCKED("\n") -#ifdef JDK8200450_TRACE - if ((nm != NULL) && (method != NULL) && !(is_readable_pointer(method) && is_readable_pointer(method->constants()))) { - ast->print("Potential CodeHeap State Analytics issue found.\n"); - if (is_readable_pointer(method)) { - ast->print(" Issue would have been detected by is_readable_pointer(" INTPTR_FORMAT "(method->constants())) check.\n", p2i(method->constants())); - } else { - ast->print(" Issue would have been detected by is_readable_pointer(" INTPTR_FORMAT "(method)) check.\n", p2i(method)); - } - STRINGSTREAM_FLUSH_LOCKED("\n") - } -#endif } else if (!blob_initialized && (this_blob != last_blob) && (this_blob != NULL)) { last_blob = this_blob; -#ifdef JDK8200450_TRACE - ast->print("Potential CodeHeap State Analytics issue found.\n"); - if (nBlobs == 0) { - ast->print(" Issue would have been detected by (nBlobs > 0) check.\n"); - } else { - if (!((address)this_blob + hdr_size == reloc_begin)) { - ast->print(" Issue would have been detected by (this(" INTPTR_FORMAT ") + header(%d) == relocation_begin(" INTPTR_FORMAT ")) check.\n", p2i(this_blob), hdr_size, p2i(reloc_begin)); - } - if (!((address)this_blob + CodeBlob::align_code_offset(hdr_size + reloc_size) == cntnt_begin)) { - ast->print(" Issue would have been detected by (this(" INTPTR_FORMAT ") + header(%d) + relocation(%d) == content_begin(" INTPTR_FORMAT ")) check.\n", p2i(this_blob), hdr_size, reloc_size, p2i(cntnt_begin)); - } - if (hdr_size != this_blob->header_size()) { - ast->print(" header_size meanwhile changed from %d to %d\n", hdr_size, this_blob->header_size()); - } - if (reloc_size != this_blob->relocation_size()) { - ast->print(" relocation_size meanwhile changed from %d to %d\n", reloc_size, this_blob->relocation_size()); - } - if (reloc_begin != (address)(this_blob->relocation_begin())) { - ast->print(" relocation_begin meanwhile changed from " INTPTR_FORMAT " to " INTPTR_FORMAT "\n", p2i(reloc_begin), p2i(this_blob->relocation_begin())); - } - if (cntnt_begin != this_blob->content_begin()) { - ast->print(" relocation_begin meanwhile changed from " INTPTR_FORMAT " to " INTPTR_FORMAT "\n", p2i(cntnt_begin), p2i(this_blob->content_begin())); - } - } STRINGSTREAM_FLUSH_LOCKED("\n") -#endif } } } // nBlobs > 0 @@ -2430,7 +2346,7 @@ void CodeHeapState::print_line_delim(outputStream* out, bufferedStream* ast, cha } CodeHeapState::blobType CodeHeapState::get_cbType(CodeBlob* cb) { - if (cb != NULL ) { + if ((cb != NULL) && is_readable_pointer(cb)) { if (cb->is_runtime_stub()) return runtimeStub; if (cb->is_deoptimization_stub()) return deoptimizationStub; if (cb->is_uncommon_trap_stub()) return uncommonTrapStub; @@ -2440,13 +2356,13 @@ CodeHeapState::blobType CodeHeapState::get_cbType(CodeBlob* cb) { if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob; if (cb->is_buffer_blob()) return bufferBlob; - if (cb->is_nmethod() ) { - if (((nmethod*)cb)->is_in_use()) return nMethod_inuse; - if (((nmethod*)cb)->is_alive() && !(((nmethod*)cb)->is_not_entrant())) return nMethod_notused; - if (((nmethod*)cb)->is_alive()) return nMethod_alive; - if (((nmethod*)cb)->is_unloaded()) return nMethod_unloaded; - if (((nmethod*)cb)->is_zombie()) return nMethod_dead; - tty->print_cr("unhandled nmethod state"); + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. + if (nm->is_zombie()) return nMethod_dead; + if (nm->is_unloaded()) return nMethod_unloaded; + if (nm->is_alive() && !(nm->is_not_entrant())) return nMethod_notused; + if (nm->is_alive()) return nMethod_alive; + if (nm->is_in_use()) return nMethod_inuse; return nMethod_dead; } } From ac401260907ee29a3ef1e0ad8d130ab17787d2e9 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Mon, 23 Apr 2018 18:04:17 -0700 Subject: [PATCH 023/102] 8202060: Add javax/net/ssl/DTLS/CipherSuite.java to ProblemList Reviewed-by: xuelei --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index d8237287ac4..40c99a5fe12 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -586,6 +586,7 @@ sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java 8026393 generic- javax/net/ssl/DTLS/PacketLossRetransmission.java 8169086 macosx-x64 javax/net/ssl/DTLS/RespondToRetransmit.java 8169086 macosx-x64 +javax/net/ssl/DTLS/CipherSuite.java 8202059 macosx-x64 sun/security/krb5/auto/UnboundSSL.java 8180265 windows-all sun/security/provider/KeyStore/DKSTest.sh 8180266 windows-all From 2ee8ddfb0d1254248e38d2f1e01c5993e3f3e312 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 20 Apr 2018 09:44:24 +0200 Subject: [PATCH 024/102] 8202074: Metaspace: If humongous chunk is added to SpaceManager, previous current chunk may not get retired correctly Reviewed-by: coleenp, asiebenborn, goetz --- src/hotspot/share/memory/metaspace.cpp | 39 ++++++++++++-------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 3ffc2926143..033003b401b 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -3407,7 +3407,16 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) { // and do an allocation from it. if (next != NULL) { // Add to this manager's list of chunks in use. - add_chunk(next, false); + // If the new chunk is humongous, it was created to serve a single large allocation. In that + // case it usually makes no sense to make it the current chunk, since the next allocation would + // need to allocate a new chunk anyway, while we would now prematurely retire a perfectly + // good chunk which could be used for more normal allocations. + bool make_current = true; + if (next->get_chunk_type() == HumongousIndex && + current_chunk() != NULL) { + make_current = false; + } + add_chunk(next, make_current); mem = next->allocate(word_size); } @@ -3564,29 +3573,17 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { // chunk for that list. ChunkIndex index = chunk_manager()->list_index(new_chunk->word_size()); - if (index != HumongousIndex) { + if (make_current) { + // If we are to make the chunk current, retire the old current chunk and replace + // it with the new chunk. retire_current_chunk(); set_current_chunk(new_chunk); - new_chunk->set_next(chunks_in_use(index)); - set_chunks_in_use(index, new_chunk); - } else { - // For null class loader data and DumpSharedSpaces, the first chunk isn't - // small, so small will be null. Link this first chunk as the current - // chunk. - if (make_current) { - // Set as the current chunk but otherwise treat as a humongous chunk. - set_current_chunk(new_chunk); - } - // Link at head. The _current_chunk only points to a humongous chunk for - // the null class loader metaspace (class and data virtual space managers) - // any humongous chunks so will not point to the tail - // of the humongous chunks list. - new_chunk->set_next(chunks_in_use(HumongousIndex)); - set_chunks_in_use(HumongousIndex, new_chunk); - - assert(new_chunk->word_size() > medium_chunk_size(), "List inconsistency"); } + // Add the new chunk at the head of its respective chunk list. + new_chunk->set_next(chunks_in_use(index)); + set_chunks_in_use(index, new_chunk); + // Add to the running sum of capacity inc_size_metrics(new_chunk->word_size()); @@ -4802,7 +4799,7 @@ ClassLoaderMetaspace::~ClassLoaderMetaspace() { void ClassLoaderMetaspace::initialize_first_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype) { Metachunk* chunk = get_initialization_chunk(type, mdtype); if (chunk != NULL) { - // Add to this manager's list of chunks in use and current_chunk(). + // Add to this manager's list of chunks in use and make it the current_chunk(). get_space_manager(mdtype)->add_chunk(chunk, true); } } From a67480f33da65c3e0d68bd5bca5572f47b11e365 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 24 Apr 2018 09:35:08 +0200 Subject: [PATCH 025/102] 8200477: Integer dot product no longer autovectorised Reviewed-by: kvn --- src/hotspot/share/opto/superword.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 295b69d4e10..f6c4162a60e 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -1943,9 +1943,14 @@ bool SuperWord::profitable(Node_List* p) { for (uint k = 0; k < use->req(); k++) { Node* n = use->in(k); if (def == n) { - // reductions can be loop carried dependences - if (def->is_reduction() && use->is_Phi()) + // reductions should only have a Phi use at the the loop + // head and out of loop uses + if (def->is_reduction() && + ((use->is_Phi() && use->in(0) == _lpt->_head) || + !_lpt->is_member(_phase->get_loop(_phase->ctrl_or_self(use))))) { + assert(i == p->size()-1, "must be last element of the pack"); continue; + } if (!is_vector_use(use, k)) { return false; } From eb393cd0150e865c27946f6a1e0d639dd63a4f15 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Mon, 23 Apr 2018 19:32:41 +0100 Subject: [PATCH 026/102] 8200556: AArch64: assertion failure in slowdebug builds Reviewed-by: adinn --- src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index f61036275ab..3fd70cb1600 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -368,7 +368,7 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { CodeBuffer cb(code_pos, instruction_size); MacroAssembler a(&cb); - a.mov(rscratch1, entry); + a.movptr(rscratch1, (uintptr_t)entry); a.br(rscratch1); ICache::invalidate_range(code_pos, instruction_size); From f69402ef4411693be10ca8a0aef35cf6847ec57b Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Tue, 24 Apr 2018 08:13:30 -0700 Subject: [PATCH 027/102] 8201281: Truncated error message with Incompatible : null Reviewed-by: mcimadamore --- .../com/sun/tools/javac/comp/Infer.java | 89 ++++++++++--------- .../com/sun/tools/javac/comp/Resolve.java | 13 +-- .../tools/javac/resources/compiler.properties | 29 +++--- .../javac/Diagnostics/6722234/T6722234d_1.out | 2 +- .../javac/Diagnostics/6722234/T6722234d_2.out | 2 +- .../javac/Diagnostics/6799605/T6799605.out | 2 +- .../NPEClearingLocalClassNameIndexesTest.out | 4 +- .../T8201281/NullInErrorMessageTest.java | 30 +++++++ .../javac/T8201281/NullInErrorMessageTest.out | 2 + .../tools/javac/diags/examples.not-yet.txt | 2 +- .../diags/examples/CantApplyDiamond1.java | 6 +- .../examples/IncompatibleEqUpperBounds.java | 6 +- .../examples/InferredDoNotConformToEq.java | 5 +- .../examples/InferredDoNotConformToUpper.java | 5 +- .../javac/diags/examples/WhereTypeVar2.java | 4 +- .../tools/javac/generics/UnsoundInference.out | 2 +- .../javac/generics/diamond/neg/Neg06.out | 6 +- .../javac/generics/diamond/neg/Neg07.out | 4 +- .../generics/inference/4941882/T4941882.out | 2 +- .../generics/inference/6315770/T6315770.out | 2 +- .../generics/inference/6611449/T6611449.out | 8 +- .../generics/inference/6638712/T6638712b.out | 2 +- .../generics/inference/6638712/T6638712d.out | 2 +- .../generics/inference/6638712/T6638712e.out | 2 +- .../generics/inference/6650759/T6650759m.out | 2 +- .../generics/inference/7177306/T7177306b.out | 2 +- .../generics/inference/7177306/T7177306e.out | 2 +- .../generics/inference/8019824/T8019824.out | 2 +- .../generics/inference/8062977/T8062977.out | 8 +- .../PrimitiveTypeBoxingTest.out | 4 +- .../tools/javac/generics/odersky/BadTest3.out | 6 +- .../generics/wildcards/6762569/T6762569b.out | 2 +- .../tools/javac/lambda/8016177/T8016177g.out | 2 +- .../tools/javac/lambda/MethodReference41.out | 4 +- .../tools/javac/lambda/MethodReference42.out | 4 +- .../tools/javac/lambda/MethodReference43.out | 6 +- .../tools/javac/lambda/MethodReference44.out | 4 +- .../tools/javac/lambda/MethodReference46.out | 4 +- .../tools/javac/lambda/MethodReference58.out | 2 +- .../tools/javac/lambda/MethodReference68.out | 4 +- .../tools/javac/lambda/TargetType02.out | 2 +- .../tools/javac/lambda/TargetType14.out | 2 +- .../tools/javac/lambda/TargetType28.out | 2 +- 43 files changed, 171 insertions(+), 124 deletions(-) create mode 100644 test/langtools/tools/javac/T8201281/NullInErrorMessageTest.java create mode 100644 test/langtools/tools/javac/T8201281/NullInErrorMessageTest.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java index 92de109e347..437fac7f9d4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.GraphUtils.DottableNode; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.Fragment; import com.sun.tools.javac.util.List; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Type.*; @@ -115,7 +116,6 @@ public class Infer { types = Types.instance(context); diags = JCDiagnostic.Factory.instance(context); log = Log.instance(context); - inferenceException = new InferenceException(diags); Options options = Options.instance(context); Source source = Source.instance(context); allowGraphInference = Feature.GRAPH_INFERENCE.allowedInSource(source) @@ -144,27 +144,32 @@ public class Infer { @Override InapplicableMethodException setMessage() { - //no message to set - return this; + throw new AssertionError("InferenceException is immutable"); } @Override InapplicableMethodException setMessage(JCDiagnostic diag) { - messages = messages.append(diag); - return this; + throw new AssertionError("InferenceException is immutable"); + } + + @Override + InapplicableMethodException setMessage(String key, Object... args) { + throw new AssertionError("InferenceException is immutable"); } @Override public JCDiagnostic getDiagnostic() { return messages.head; } - - void clear() { - messages = List.nil(); - } } - protected final InferenceException inferenceException; + InferenceException error(JCDiagnostic diag) { + InferenceException result = new InferenceException(diags); + if (diag != null) { + result.messages = result.messages.append(diag); + } + return result; + } // /** @@ -183,7 +188,6 @@ public class Infer { Warner warn) throws InferenceException { //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG final InferenceContext inferenceContext = new InferenceContext(this, tvars); //B0 - inferenceException.clear(); try { DeferredAttr.DeferredAttrContext deferredAttrContext = resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn); @@ -315,7 +319,6 @@ public class Infer { */ Type check(Attr.ResultInfo resultInfo) { Warner noWarnings = new Warner(null); - inferenceException.clear(); List saved_undet = null; try { /** we need to save the inference context before generating target type constraints. @@ -430,9 +433,7 @@ public class Infer { if (!resultInfo.checkContext.compatible(qtype, rsInfoInfContext.asUndetVar(to), retWarn) || //unchecked conversion is not allowed in source 7 mode (!allowGraphInference && retWarn.hasLint(Lint.LintCategory.UNCHECKED))) { - throw inferenceException - .setMessage("infer.no.conforming.instance.exists", - inferenceContext.restvars(), mt.getReturnType(), to); + throw error(diags.fragment(Fragments.InferNoConformingInstanceExists(inferenceContext.restvars(), mt.getReturnType(), to))); } return from; } @@ -1269,41 +1270,49 @@ public class Infer { * Incorporation error: mismatch between inferred type and given bound. */ void reportInstError(UndetVar uv, InferenceBound ib) { - reportInferenceError( - String.format("inferred.do.not.conform.to.%s.bounds", StringUtils.toLowerCase(ib.name())), - uv.getInst(), - uv.getBounds(ib)); + switch (ib) { + case EQ: + throw error(diags.fragment(Fragments.InferredDoNotConformToEqBounds(uv.getInst(), uv.getBounds(ib)))); + case LOWER: + throw error(diags.fragment(Fragments.InferredDoNotConformToLowerBounds(uv.getInst(), uv.getBounds(ib)))); + case UPPER: + throw error(diags.fragment(Fragments.InferredDoNotConformToUpperBounds(uv.getInst(), uv.getBounds(ib)))); + } } /** * Incorporation error: mismatch between two (or more) bounds of same kind. */ void reportBoundError(UndetVar uv, InferenceBound ib) { - reportInferenceError( - String.format("incompatible.%s.bounds", StringUtils.toLowerCase(ib.name())), - uv.qtype, - uv.getBounds(ib)); + switch (ib) { + case EQ: + throw error(diags.fragment(Fragments.IncompatibleEqBounds(uv.qtype, uv.getBounds(ib)))); + case UPPER: + throw error(diags.fragment(Fragments.IncompatibleUpperBounds(uv.qtype, uv.getBounds(ib)))); + case LOWER: + throw new AssertionError("this case shouldn't happen"); + } } /** * Incorporation error: mismatch between two (or more) bounds of different kinds. */ void reportBoundError(UndetVar uv, InferenceBound ib1, InferenceBound ib2) { - reportInferenceError( - String.format("incompatible.%s.%s.bounds", - StringUtils.toLowerCase(ib1.name()), - StringUtils.toLowerCase(ib2.name())), + throw error(diags.fragment(Fragments.IncompatibleBounds( uv.qtype, - uv.getBounds(ib1), - uv.getBounds(ib2)); + getBoundFragment(ib1, uv.getBounds(ib1)), + getBoundFragment(ib2, uv.getBounds(ib2))))); } - /** - * Helper method: reports an inference error. - */ - void reportInferenceError(String key, Object... args) { - throw inferenceException.setMessage(key, args); + Fragment getBoundFragment(InferenceBound ib, List types) { + switch (ib) { + case EQ: return Fragments.EqBounds(types); + case LOWER: return Fragments.LowerBounds(types); + case UPPER: return Fragments.UpperBounds(types); + } + throw new AssertionError("can't get to this place"); } + // // @@ -1456,9 +1465,7 @@ public class Infer { //note: lobounds should have at least one element Type owntype = lobounds.tail.tail == null ? lobounds.head : infer.types.lub(lobounds); if (owntype.isPrimitive() || owntype.hasTag(ERROR)) { - throw infer.inferenceException - .setMessage("no.unique.minimal.instance.exists", - uv.qtype, lobounds); + throw infer.error(infer.diags.fragment(Fragments.NoUniqueMinimalInstanceExists(uv.qtype, lobounds))); } else { return owntype; } @@ -1499,9 +1506,7 @@ public class Infer { //note: hibounds should have at least one element Type owntype = hibounds.tail.tail == null ? hibounds.head : infer.types.glb(hibounds); if (owntype.isPrimitive() || owntype.hasTag(ERROR)) { - throw infer.inferenceException - .setMessage("no.unique.maximal.instance.exists", - uv.qtype, hibounds); + throw infer.error(infer.diags.fragment(Fragments.NoUniqueMaximalInstanceExists(uv.qtype, hibounds))); } else { return owntype; } @@ -1677,7 +1682,7 @@ public class Infer { } } //no progress - throw inferenceException.setMessage(); + throw error(null); } } catch (InferenceException ex) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 374049f9515..5486953fd0d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,6 @@ import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.DeferredAttr.AttrMode; import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; import com.sun.tools.javac.comp.DeferredAttr.DeferredType; -import com.sun.tools.javac.comp.Infer.FreeTypeListener; import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate; import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.Template; import com.sun.tools.javac.comp.Resolve.ReferenceLookupResult.StaticKind; @@ -60,7 +59,6 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.function.BiFunction; @@ -71,6 +69,8 @@ import java.util.stream.Stream; import javax.lang.model.element.ElementVisitor; +import com.sun.tools.javac.comp.Infer.InferenceException; + import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Flags.STATIC; @@ -811,8 +811,6 @@ public class Resolve { protected void reportMC(DiagnosticPosition pos, MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { boolean inferDiag = inferenceContext != infer.emptyContext; - InapplicableMethodException ex = inferDiag ? - infer.inferenceException : inapplicableMethodException; if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) { Object[] args2 = new Object[args.length + 1]; System.arraycopy(args, 0, args2, 1, args.length); @@ -820,7 +818,10 @@ public class Resolve { args = args2; } String key = inferDiag ? diag.inferKey : diag.basicKey; - throw ex.setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)); + throw inferDiag ? + infer.error(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)) : + inapplicableMethodException + .setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)); } public MethodCheck mostSpecificCheck(List actuals) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index a0209aaa8d1..a7aff52ac30 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2302,6 +2302,7 @@ compiler.misc.type.parameter=\ compiler.misc.no.unique.maximal.instance.exists=\ no unique maximal instance exists for type variable {0} with upper bounds {1} +# 0: type, 1: list of type compiler.misc.no.unique.minimal.instance.exists=\ no unique minimal instance exists for type variable {0} with lower bounds {1} @@ -2313,23 +2314,23 @@ compiler.misc.incompatible.upper.bounds=\ compiler.misc.incompatible.eq.bounds=\ inference variable {0} has incompatible equality constraints {1} -# 0: type, 1: list of type, 2: list of type -compiler.misc.incompatible.eq.upper.bounds=\ +# 0: type, 1: fragment, 2: fragment +compiler.misc.incompatible.bounds=\ inference variable {0} has incompatible bounds\n\ - equality constraints: {1}\n\ - upper bounds: {2} + {1}\n\ + {2} -# 0: type, 1: list of type, 2: list of type -compiler.misc.incompatible.upper.lower.bounds=\ - inference variable {0} has incompatible bounds\n\ - upper bounds: {1}\n\ - lower bounds: {2} +# 0: list of type +compiler.misc.lower.bounds=\ + lower bounds: {0} -# 0: type, 1: list of type, 2: list of type -compiler.misc.incompatible.eq.lower.bounds=\ - inference variable {0} has incompatible bounds\n\ - equality constraints: {1}\n\ - lower bounds: {2} +# 0: list of type +compiler.misc.eq.bounds=\ + equality constraints: {0} + +# 0: list of type +compiler.misc.upper.bounds=\ + lower bounds: {0} # 0: list of type, 1: type, 2: type compiler.misc.infer.no.conforming.instance.exists=\ diff --git a/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_1.out b/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_1.out index fc2059a8fcc..0977036216c 100644 --- a/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_1.out +++ b/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_1.out @@ -1,3 +1,3 @@ -T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.lower.bounds: Z, T6722234d.A,java.lang.Object, T6722234d.B,T6722234d.A) +T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: T6722234d.A,java.lang.Object), (compiler.misc.lower.bounds: T6722234d.B,T6722234d.A)) - compiler.misc.where.description.typevar: Z,{(compiler.misc.where.typevar: Z, java.lang.Object, kindname.method, m(Z,Z))} 1 error diff --git a/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_2.out b/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_2.out index ff9449aee60..3db8e16f112 100644 --- a/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_2.out +++ b/test/langtools/tools/javac/Diagnostics/6722234/T6722234d_2.out @@ -1,3 +1,3 @@ -T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.lower.bounds: Z, T6722234d.A,Object, T6722234d.B,T6722234d.A) +T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: T6722234d.A,Object), (compiler.misc.lower.bounds: T6722234d.B,T6722234d.A)) - compiler.misc.where.description.typevar: Z,{(compiler.misc.where.typevar: Z, Object, kindname.method, m(Z,Z))} 1 error diff --git a/test/langtools/tools/javac/Diagnostics/6799605/T6799605.out b/test/langtools/tools/javac/Diagnostics/6799605/T6799605.out index 690c7fdd6bb..f0952342dd3 100644 --- a/test/langtools/tools/javac/Diagnostics/6799605/T6799605.out +++ b/test/langtools/tools/javac/Diagnostics/6799605/T6799605.out @@ -1,4 +1,4 @@ -T6799605.java:17:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605,{(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605), (compiler.misc.incompatible.eq.upper.bounds: T, compiler.misc.type.captureof: 1, ?, T6799605)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605,T6799605), (compiler.misc.infer.arg.length.mismatch: T))} +T6799605.java:17:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605,{(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605), (compiler.misc.incompatible.bounds: T, (compiler.misc.eq.bounds: compiler.misc.type.captureof: 1, ?), (compiler.misc.upper.bounds: T6799605))),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605,T6799605), (compiler.misc.infer.arg.length.mismatch: T))} T6799605.java:18:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605,T6799605,{(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605), (compiler.misc.incompatible.eq.bounds: T, compiler.misc.type.captureof: 2, ?,compiler.misc.type.captureof: 1, ?)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605,T6799605), (compiler.misc.infer.arg.length.mismatch: T))} T6799605.java:19:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605,T6799605,T6799605,{(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, m(T6799605,T6799605,T6799605), (compiler.misc.incompatible.eq.bounds: T, compiler.misc.type.captureof: 3, ?,compiler.misc.type.captureof: 2, ?,compiler.misc.type.captureof: 1, ?))} 3 errors diff --git a/test/langtools/tools/javac/T8171325/NPEClearingLocalClassNameIndexesTest.out b/test/langtools/tools/javac/T8171325/NPEClearingLocalClassNameIndexesTest.out index 809d0c25961..df30b6bfa95 100644 --- a/test/langtools/tools/javac/T8171325/NPEClearingLocalClassNameIndexesTest.out +++ b/test/langtools/tools/javac/T8171325/NPEClearingLocalClassNameIndexesTest.out @@ -1,6 +1,6 @@ -NPEClearingLocalClassNameIndexesTest.java:18:9: compiler.err.cant.apply.symbol: kindname.method, f, java.util.List, java.lang.String, kindname.class, NPEClearingLocalClassNameIndexesTest, (compiler.misc.incompatible.upper.lower.bounds: C, java.lang.Object,java.util.List, java.lang.String) +NPEClearingLocalClassNameIndexesTest.java:18:9: compiler.err.cant.apply.symbol: kindname.method, f, java.util.List, java.lang.String, kindname.class, NPEClearingLocalClassNameIndexesTest, (compiler.misc.incompatible.bounds: C, (compiler.misc.upper.bounds: java.lang.Object,java.util.List), (compiler.misc.lower.bounds: java.lang.String)) NPEClearingLocalClassNameIndexesTest.java:18:42: compiler.err.cant.resolve.location: kindname.class, NoSuch, , , (compiler.misc.location: kindname.class, NPEClearingLocalClassNameIndexesTest, null) -NPEClearingLocalClassNameIndexesTest.java:19:9: compiler.err.cant.apply.symbol: kindname.method, f, java.util.List, java.lang.String, kindname.class, NPEClearingLocalClassNameIndexesTest, (compiler.misc.incompatible.upper.lower.bounds: C, java.lang.Object,java.util.List, java.lang.String) +NPEClearingLocalClassNameIndexesTest.java:19:9: compiler.err.cant.apply.symbol: kindname.method, f, java.util.List, java.lang.String, kindname.class, NPEClearingLocalClassNameIndexesTest, (compiler.misc.incompatible.bounds: C, (compiler.misc.upper.bounds: java.lang.Object,java.util.List), (compiler.misc.lower.bounds: java.lang.String)) NPEClearingLocalClassNameIndexesTest.java:19:42: compiler.err.cant.resolve.location: kindname.class, NoSuch, , , (compiler.misc.location: kindname.class, NPEClearingLocalClassNameIndexesTest, null) NPEClearingLocalClassNameIndexesTest.java:19:49: compiler.err.type.found.req: int, (compiler.misc.type.req.ref) 5 errors diff --git a/test/langtools/tools/javac/T8201281/NullInErrorMessageTest.java b/test/langtools/tools/javac/T8201281/NullInErrorMessageTest.java new file mode 100644 index 00000000000..7ff9e6e7766 --- /dev/null +++ b/test/langtools/tools/javac/T8201281/NullInErrorMessageTest.java @@ -0,0 +1,30 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8201281 + * @summary Truncated error message with Incompatible : null + * @compile/fail/ref=NullInErrorMessageTest.out -XDrawDiagnostics NullInErrorMessageTest.java + */ + +import java.util.concurrent.CompletionStage; +import java.util.function.Function; +import java.util.function.Supplier; + +public class NullInErrorMessageTest { + private CompletionStage test() { + return null; + } + + private CompletionStage test2() { + return null; + } + + public static Function test3() { + return null; + } + + private Supplier> createSupplier() { + return () -> test().thenCompose(value -> { + return () -> test2().exceptionally(test3()); + }); + } +} diff --git a/test/langtools/tools/javac/T8201281/NullInErrorMessageTest.out b/test/langtools/tools/javac/T8201281/NullInErrorMessageTest.out new file mode 100644 index 00000000000..1a4975c96ab --- /dev/null +++ b/test/langtools/tools/javac/T8201281/NullInErrorMessageTest.out @@ -0,0 +1,2 @@ +NullInErrorMessageTest.java:26:40: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.infer.no.conforming.assignment.exists: U, (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.not.a.functional.intf.1: java.util.concurrent.CompletionStage, (compiler.misc.incompatible.abstracts: kindname.interface, java.util.concurrent.CompletionStage))))) +1 error diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 0072d89c1e0..3fa4b2ac5ac 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -73,7 +73,6 @@ compiler.misc.kindname.static compiler.misc.kindname.type.variable compiler.misc.kindname.type.variable.bound compiler.misc.kindname.value -compiler.misc.incompatible.eq.lower.bounds # cannot happen? compiler.misc.module.name.mismatch compiler.misc.module.non.zero.opens # bad class file compiler.misc.no.unique.minimal.instance.exists @@ -151,6 +150,7 @@ compiler.misc.locn.module_path # fragment uninter compiler.misc.locn.module_source_path # fragment uninteresting in and of itself compiler.misc.locn.system_modules # fragment uninteresting in and of itself compiler.misc.locn.upgrade_module_path # fragment uninteresting in and of itself +compiler.misc.inferred.do.not.conform.to.eq.bounds # hard to generate, could probably be removed # The following are new module-related messages, that need new examples to be created compiler.err.duplicate.module.on.path diff --git a/test/langtools/tools/javac/diags/examples/CantApplyDiamond1.java b/test/langtools/tools/javac/diags/examples/CantApplyDiamond1.java index 18ca0a662a3..43ade850112 100644 --- a/test/langtools/tools/javac/diags/examples/CantApplyDiamond1.java +++ b/test/langtools/tools/javac/diags/examples/CantApplyDiamond1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,9 @@ // key: compiler.err.prob.found.req // key: compiler.misc.cant.apply.diamond.1 -// key: compiler.misc.incompatible.eq.upper.bounds +// key: compiler.misc.incompatible.bounds +// key: compiler.misc.eq.bounds +// key: compiler.misc.upper.bounds // key: compiler.misc.diamond class CantApplyDiamond1 { diff --git a/test/langtools/tools/javac/diags/examples/IncompatibleEqUpperBounds.java b/test/langtools/tools/javac/diags/examples/IncompatibleEqUpperBounds.java index 83651fe3ff1..1edac60b647 100644 --- a/test/langtools/tools/javac/diags/examples/IncompatibleEqUpperBounds.java +++ b/test/langtools/tools/javac/diags/examples/IncompatibleEqUpperBounds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,9 @@ */ //key: compiler.err.cant.apply.symbol -//key: compiler.misc.incompatible.eq.upper.bounds +//key: compiler.misc.incompatible.bounds +//key: compiler.misc.eq.bounds +//key: compiler.misc.upper.bounds import java.util.List; diff --git a/test/langtools/tools/javac/diags/examples/InferredDoNotConformToEq.java b/test/langtools/tools/javac/diags/examples/InferredDoNotConformToEq.java index c5beec01484..17fe8a3e5fe 100644 --- a/test/langtools/tools/javac/diags/examples/InferredDoNotConformToEq.java +++ b/test/langtools/tools/javac/diags/examples/InferredDoNotConformToEq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,8 @@ */ // key: compiler.err.cant.apply.symbol -// key: compiler.misc.inferred.do.not.conform.to.eq.bounds +// key: compiler.misc.inconvertible.types +// key: compiler.misc.infer.no.conforming.assignment.exists // options: -source 7 -Xlint:-options import java.util.*; diff --git a/test/langtools/tools/javac/diags/examples/InferredDoNotConformToUpper.java b/test/langtools/tools/javac/diags/examples/InferredDoNotConformToUpper.java index ca45b461ec2..fa43ed14e03 100644 --- a/test/langtools/tools/javac/diags/examples/InferredDoNotConformToUpper.java +++ b/test/langtools/tools/javac/diags/examples/InferredDoNotConformToUpper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,8 @@ */ // key: compiler.err.cant.apply.symbol -// key: compiler.misc.inferred.do.not.conform.to.upper.bounds +// key: compiler.misc.inconvertible.types +// key: compiler.misc.infer.no.conforming.assignment.exists // options: -source 7 -Xlint:-options import java.util.*; diff --git a/test/langtools/tools/javac/diags/examples/WhereTypeVar2.java b/test/langtools/tools/javac/diags/examples/WhereTypeVar2.java index 38d160f0e12..8dcb69bdca4 100644 --- a/test/langtools/tools/javac/diags/examples/WhereTypeVar2.java +++ b/test/langtools/tools/javac/diags/examples/WhereTypeVar2.java @@ -21,10 +21,12 @@ * questions. */ -// key: compiler.misc.incompatible.upper.lower.bounds +// key: compiler.misc.incompatible.bounds // key: compiler.misc.where.description.typevar // key: compiler.misc.where.typevar // key: compiler.err.prob.found.req +// key: compiler.misc.lower.bounds +// key: compiler.misc.upper.bounds // options: --diags=formatterOptions=where // run: simple diff --git a/test/langtools/tools/javac/generics/UnsoundInference.out b/test/langtools/tools/javac/generics/UnsoundInference.out index 5eb5c9dfd80..b679945e90b 100644 --- a/test/langtools/tools/javac/generics/UnsoundInference.out +++ b/test/langtools/tools/javac/generics/UnsoundInference.out @@ -1,2 +1,2 @@ -UnsoundInference.java:18:9: compiler.err.cant.apply.symbol: kindname.method, transferBug, Var[],java.util.Collection, java.lang.Object[],java.util.ArrayList, kindname.class, UnsoundInference, (compiler.misc.incompatible.eq.lower.bounds: Var, java.lang.String, java.lang.Object) +UnsoundInference.java:18:9: compiler.err.cant.apply.symbol: kindname.method, transferBug, Var[],java.util.Collection, java.lang.Object[],java.util.ArrayList, kindname.class, UnsoundInference, (compiler.misc.incompatible.bounds: Var, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.lower.bounds: java.lang.Object)) 1 error diff --git a/test/langtools/tools/javac/generics/diamond/neg/Neg06.out b/test/langtools/tools/javac/generics/diamond/neg/Neg06.out index 8923784a702..28c11d00033 100644 --- a/test/langtools/tools/javac/generics/diamond/neg/Neg06.out +++ b/test/langtools/tools/javac/generics/diamond/neg/Neg06.out @@ -1,4 +1,4 @@ -Neg06.java:18:36: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.IFoo), (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number)) -Neg06.java:19:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number)) -Neg06.java:20:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number)) +Neg06.java:18:36: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.IFoo), (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Number))) +Neg06.java:19:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Number))) +Neg06.java:20:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Number))) 3 errors diff --git a/test/langtools/tools/javac/generics/diamond/neg/Neg07.out b/test/langtools/tools/javac/generics/diamond/neg/Neg07.out index de34f51a952..6b24892b876 100644 --- a/test/langtools/tools/javac/generics/diamond/neg/Neg07.out +++ b/test/langtools/tools/javac/generics/diamond/neg/Neg07.out @@ -1,3 +1,3 @@ -Neg07.java:17:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.String) -Neg07.java:18:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.String) +Neg07.java:17:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.String)) +Neg07.java:18:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.String)) 2 errors diff --git a/test/langtools/tools/javac/generics/inference/4941882/T4941882.out b/test/langtools/tools/javac/generics/inference/4941882/T4941882.out index 30426bb7c55..252773a6fa1 100644 --- a/test/langtools/tools/javac/generics/inference/4941882/T4941882.out +++ b/test/langtools/tools/javac/generics/inference/4941882/T4941882.out @@ -1,2 +1,2 @@ -T4941882.java:13:17: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.lower.bounds: T, java.lang.Object[],java.lang.Object, float[],int[]) +T4941882.java:13:17: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: java.lang.Object[],java.lang.Object), (compiler.misc.lower.bounds: float[],int[])) 1 error diff --git a/test/langtools/tools/javac/generics/inference/6315770/T6315770.out b/test/langtools/tools/javac/generics/inference/6315770/T6315770.out index bb22516c7c2..a51dda5e447 100644 --- a/test/langtools/tools/javac/generics/inference/6315770/T6315770.out +++ b/test/langtools/tools/javac/generics/inference/6315770/T6315770.out @@ -1,3 +1,3 @@ T6315770.java:16:42: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.bounds: T, java.lang.String,java.lang.Integer,java.lang.Runnable) -T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.lower.bounds: T, java.lang.Integer,java.lang.Runnable, java.lang.String) +T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: java.lang.Integer,java.lang.Runnable), (compiler.misc.lower.bounds: java.lang.String)) 2 errors diff --git a/test/langtools/tools/javac/generics/inference/6611449/T6611449.out b/test/langtools/tools/javac/generics/inference/6611449/T6611449.out index a0bc8d457a7..2a697f26812 100644 --- a/test/langtools/tools/javac/generics/inference/6611449/T6611449.out +++ b/test/langtools/tools/javac/generics/inference/6611449/T6611449.out @@ -1,5 +1,5 @@ -T6611449.java:18:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T), (compiler.misc.incompatible.upper.lower.bounds: T, S, java.lang.Integer)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T,T), (compiler.misc.infer.arg.length.mismatch: T))} -T6611449.java:19:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T,T), (compiler.misc.incompatible.upper.lower.bounds: T, S, java.lang.Integer))} -T6611449.java:20:9: compiler.err.cant.apply.symbol: kindname.method, m1, T, int, kindname.class, T6611449, (compiler.misc.incompatible.upper.lower.bounds: T, S, java.lang.Integer) -T6611449.java:21:9: compiler.err.cant.apply.symbol: kindname.method, m2, T,T, int,int, kindname.class, T6611449, (compiler.misc.incompatible.upper.lower.bounds: T, S, java.lang.Integer) +T6611449.java:18:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T), (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: S), (compiler.misc.lower.bounds: java.lang.Integer))),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T,T), (compiler.misc.infer.arg.length.mismatch: T))} +T6611449.java:19:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, T6611449(T,T), (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: S), (compiler.misc.lower.bounds: java.lang.Integer)))} +T6611449.java:20:9: compiler.err.cant.apply.symbol: kindname.method, m1, T, int, kindname.class, T6611449, (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: S), (compiler.misc.lower.bounds: java.lang.Integer)) +T6611449.java:21:9: compiler.err.cant.apply.symbol: kindname.method, m2, T,T, int,int, kindname.class, T6611449, (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: S), (compiler.misc.lower.bounds: java.lang.Integer)) 4 errors diff --git a/test/langtools/tools/javac/generics/inference/6638712/T6638712b.out b/test/langtools/tools/javac/generics/inference/6638712/T6638712b.out index 9f72699204c..9b759e8651a 100644 --- a/test/langtools/tools/javac/generics/inference/6638712/T6638712b.out +++ b/test/langtools/tools/javac/generics/inference/6638712/T6638712b.out @@ -1,2 +1,2 @@ -T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: T, java.lang.Integer, java.lang.String,java.lang.Object) +T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: T, (compiler.misc.eq.bounds: java.lang.Integer), (compiler.misc.upper.bounds: java.lang.String,java.lang.Object)) 1 error diff --git a/test/langtools/tools/javac/generics/inference/6638712/T6638712d.out b/test/langtools/tools/javac/generics/inference/6638712/T6638712d.out index b1137d0569c..75b169349d3 100644 --- a/test/langtools/tools/javac/generics/inference/6638712/T6638712d.out +++ b/test/langtools/tools/javac/generics/inference/6638712/T6638712d.out @@ -1,2 +1,2 @@ -T6638712d.java:16:9: compiler.err.cant.apply.symbol: kindname.method, m, U,java.util.List>, int,java.util.List>, kindname.class, T6638712d, (compiler.misc.incompatible.eq.lower.bounds: U, java.lang.String, java.lang.Integer) +T6638712d.java:16:9: compiler.err.cant.apply.symbol: kindname.method, m, U,java.util.List>, int,java.util.List>, kindname.class, T6638712d, (compiler.misc.incompatible.bounds: U, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.lower.bounds: java.lang.Integer)) 1 error diff --git a/test/langtools/tools/javac/generics/inference/6638712/T6638712e.out b/test/langtools/tools/javac/generics/inference/6638712/T6638712e.out index 18adee2c0cd..3922e561aad 100644 --- a/test/langtools/tools/javac/generics/inference/6638712/T6638712e.out +++ b/test/langtools/tools/javac/generics/inference/6638712/T6638712e.out @@ -1,2 +1,2 @@ -T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.Object, java.lang.Boolean,java.lang.Object) +T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.Object), (compiler.misc.upper.bounds: java.lang.Boolean,java.lang.Object)) 1 error diff --git a/test/langtools/tools/javac/generics/inference/6650759/T6650759m.out b/test/langtools/tools/javac/generics/inference/6650759/T6650759m.out index 3987c2b4169..3819a4cfe9b 100644 --- a/test/langtools/tools/javac/generics/inference/6650759/T6650759m.out +++ b/test/langtools/tools/javac/generics/inference/6650759/T6650759m.out @@ -1,2 +1,2 @@ -T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.lower.bounds: Z, java.lang.Integer,java.lang.Object, java.lang.String) +T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: java.lang.Integer,java.lang.Object), (compiler.misc.lower.bounds: java.lang.String)) 1 error diff --git a/test/langtools/tools/javac/generics/inference/7177306/T7177306b.out b/test/langtools/tools/javac/generics/inference/7177306/T7177306b.out index d0d5a0c373f..9d441e97d0e 100644 --- a/test/langtools/tools/javac/generics/inference/7177306/T7177306b.out +++ b/test/langtools/tools/javac/generics/inference/7177306/T7177306b.out @@ -1,2 +1,2 @@ -T7177306b.java:15:9: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List,S,java.lang.Class, java.util.List,java.util.List,java.lang.Class, kindname.class, T7177306b, (compiler.misc.incompatible.eq.upper.bounds: T, java.lang.String, java.lang.Integer,java.lang.Object) +T7177306b.java:15:9: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List,S,java.lang.Class, java.util.List,java.util.List,java.lang.Class, kindname.class, T7177306b, (compiler.misc.incompatible.bounds: T, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Integer,java.lang.Object)) 1 error diff --git a/test/langtools/tools/javac/generics/inference/7177306/T7177306e.out b/test/langtools/tools/javac/generics/inference/7177306/T7177306e.out index 8ac917bf834..420a86cc5b4 100644 --- a/test/langtools/tools/javac/generics/inference/7177306/T7177306e.out +++ b/test/langtools/tools/javac/generics/inference/7177306/T7177306e.out @@ -1,2 +1,2 @@ -T7177306e.java:16:8: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List, java.util.List>, kindname.class, T7177306e, (compiler.misc.incompatible.eq.upper.bounds: U, java.util.List, java.util.List) +T7177306e.java:16:8: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List, java.util.List>, kindname.class, T7177306e, (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.Object, compiler.misc.type.captureof: 1, ?) 1 error diff --git a/test/langtools/tools/javac/generics/inference/8019824/T8019824.out b/test/langtools/tools/javac/generics/inference/8019824/T8019824.out index a30c235f910..6ce7ba7381d 100644 --- a/test/langtools/tools/javac/generics/inference/8019824/T8019824.out +++ b/test/langtools/tools/javac/generics/inference/8019824/T8019824.out @@ -1,2 +1,2 @@ -T8019824.java:9:25: compiler.err.cant.apply.symbol: kindname.method, make, java.lang.Class, java.lang.Class>, kindname.class, T8019824, (compiler.misc.incompatible.eq.upper.bounds: C, compiler.misc.type.captureof: 1, ? extends T8019824.Foo, T8019824.Foo) +T8019824.java:9:25: compiler.err.cant.apply.symbol: kindname.method, make, java.lang.Class, java.lang.Class>, kindname.class, T8019824, (compiler.misc.incompatible.bounds: C, (compiler.misc.eq.bounds: compiler.misc.type.captureof: 1, ? extends T8019824.Foo), (compiler.misc.upper.bounds: T8019824.Foo)) 1 error diff --git a/test/langtools/tools/javac/generics/inference/8062977/T8062977.out b/test/langtools/tools/javac/generics/inference/8062977/T8062977.out index 1606baecb57..abf2fc44582 100644 --- a/test/langtools/tools/javac/generics/inference/8062977/T8062977.out +++ b/test/langtools/tools/javac/generics/inference/8062977/T8062977.out @@ -1,5 +1,5 @@ -T8062977.java:15:31: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.util.List[]&java.lang.Iterable, java.util.List[],java.lang.Iterable,java.lang.Object) -T8062977.java:21:29: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Iterable[]&java.util.List, java.util.List,java.lang.Iterable[],java.lang.Object) -T8062977.java:26:31: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.util.List[], java.util.List[],java.lang.Iterable[][],java.lang.Object) -T8062977.java:27:29: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Iterable[][]&java.util.List, java.util.List,java.lang.Iterable[][],java.lang.Object) +T8062977.java:15:31: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,B, (compiler.misc.inconvertible.types: java.lang.Class>, java.lang.Class)) +T8062977.java:21:29: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,B, (compiler.misc.inconvertible.types: java.lang.Class[]>, java.lang.Class)) +T8062977.java:26:31: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,B, (compiler.misc.inconvertible.types: java.lang.Class[][]>, java.lang.Class)) +T8062977.java:27:29: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,B, (compiler.misc.inconvertible.types: java.lang.Class[][]>, java.lang.Class)) 4 errors diff --git a/test/langtools/tools/javac/generics/inference/EagerReturnTypeResolution/PrimitiveTypeBoxingTest.out b/test/langtools/tools/javac/generics/inference/EagerReturnTypeResolution/PrimitiveTypeBoxingTest.out index 21c9a11b4a4..d3bba603183 100644 --- a/test/langtools/tools/javac/generics/inference/EagerReturnTypeResolution/PrimitiveTypeBoxingTest.out +++ b/test/langtools/tools/javac/generics/inference/EagerReturnTypeResolution/PrimitiveTypeBoxingTest.out @@ -1,3 +1,3 @@ -PrimitiveTypeBoxingTest.java:19:9: compiler.err.cant.apply.symbol: kindname.method, m1, PrimitiveTypeBoxingTest.F,Z, @12,int, kindname.class, PrimitiveTypeBoxingTest, (compiler.misc.incompatible.upper.lower.bounds: Z, java.lang.Long,java.lang.Object, java.lang.Integer) -PrimitiveTypeBoxingTest.java:20:9: compiler.err.cant.apply.symbol: kindname.method, m2, Z,PrimitiveTypeBoxingTest.F, int,@16, kindname.class, PrimitiveTypeBoxingTest, (compiler.misc.incompatible.upper.lower.bounds: Z, java.lang.Long,java.lang.Object, java.lang.Integer) +PrimitiveTypeBoxingTest.java:19:9: compiler.err.cant.apply.symbol: kindname.method, m1, PrimitiveTypeBoxingTest.F,Z, @12,int, kindname.class, PrimitiveTypeBoxingTest, (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: java.lang.Long,java.lang.Object), (compiler.misc.lower.bounds: java.lang.Integer)) +PrimitiveTypeBoxingTest.java:20:9: compiler.err.cant.apply.symbol: kindname.method, m2, Z,PrimitiveTypeBoxingTest.F, int,@16, kindname.class, PrimitiveTypeBoxingTest, (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: java.lang.Long,java.lang.Object), (compiler.misc.lower.bounds: java.lang.Integer)) 2 errors diff --git a/test/langtools/tools/javac/generics/odersky/BadTest3.out b/test/langtools/tools/javac/generics/odersky/BadTest3.out index 4df21d6c832..960c27b2d07 100644 --- a/test/langtools/tools/javac/generics/odersky/BadTest3.out +++ b/test/langtools/tools/javac/generics/odersky/BadTest3.out @@ -1,4 +1,4 @@ -BadTest3.java:31:34: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: B, java.lang.String, BadTest3.Ord) -BadTest3.java:33:13: compiler.err.cant.apply.symbol: kindname.method, f, B, List, kindname.class, BadTest3.Main, (compiler.misc.incompatible.upper.lower.bounds: B, BadTest3.I,BadTest3.J, List) -BadTest3.java:35:19: compiler.err.cant.apply.symbol: kindname.method, f, B, List, kindname.class, BadTest3.Main, (compiler.misc.incompatible.upper.lower.bounds: B, BadTest3.I,BadTest3.J, List) +BadTest3.java:31:34: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: B, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: BadTest3.Ord)) +BadTest3.java:33:13: compiler.err.cant.apply.symbol: kindname.method, f, B, List, kindname.class, BadTest3.Main, (compiler.misc.incompatible.bounds: B, (compiler.misc.upper.bounds: BadTest3.I,BadTest3.J), (compiler.misc.lower.bounds: List)) +BadTest3.java:35:19: compiler.err.cant.apply.symbol: kindname.method, f, B, List, kindname.class, BadTest3.Main, (compiler.misc.incompatible.bounds: B, (compiler.misc.upper.bounds: BadTest3.I,BadTest3.J), (compiler.misc.lower.bounds: List)) 3 errors diff --git a/test/langtools/tools/javac/generics/wildcards/6762569/T6762569b.out b/test/langtools/tools/javac/generics/wildcards/6762569/T6762569b.out index f815792f8d0..32224841559 100644 --- a/test/langtools/tools/javac/generics/wildcards/6762569/T6762569b.out +++ b/test/langtools/tools/javac/generics/wildcards/6762569/T6762569b.out @@ -1,2 +1,2 @@ -T6762569b.java:13:9: compiler.err.cant.apply.symbol: kindname.method, m, T,java.util.List>, java.lang.String,java.util.List>, kindname.class, T6762569b, (compiler.misc.incompatible.upper.lower.bounds: T, java.lang.Number,java.lang.Object, java.lang.String) +T6762569b.java:13:9: compiler.err.cant.apply.symbol: kindname.method, m, T,java.util.List>, java.lang.String,java.util.List>, kindname.class, T6762569b, (compiler.misc.incompatible.bounds: T, (compiler.misc.upper.bounds: java.lang.Number,java.lang.Object), (compiler.misc.lower.bounds: java.lang.String)) 1 error diff --git a/test/langtools/tools/javac/lambda/8016177/T8016177g.out b/test/langtools/tools/javac/lambda/8016177/T8016177g.out index 45936930548..8fc06fc1264 100644 --- a/test/langtools/tools/javac/lambda/8016177/T8016177g.out +++ b/test/langtools/tools/javac/lambda/8016177/T8016177g.out @@ -1,3 +1,3 @@ -T8016177g.java:34:14: compiler.err.cant.apply.symbol: kindname.method, print, java.lang.String, Test.Person, kindname.class, Test, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.upper.lower.bounds: R, java.lang.String,java.lang.Object, Test.Person)) +T8016177g.java:34:14: compiler.err.cant.apply.symbol: kindname.method, print, java.lang.String, Test.Person, kindname.class, Test, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.bounds: R, (compiler.misc.upper.bounds: java.lang.String,java.lang.Object), (compiler.misc.lower.bounds: Test.Person))) T8016177g.java:35:20: compiler.err.cant.apply.symbol: kindname.method, abs, int, java.lang.Double, kindname.class, Test, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Double, java.lang.Integer,java.lang.Object)) 2 errors diff --git a/test/langtools/tools/javac/lambda/MethodReference41.out b/test/langtools/tools/javac/lambda/MethodReference41.out index 69da91c28fa..8b2e1a72b7e 100644 --- a/test/langtools/tools/javac/lambda/MethodReference41.out +++ b/test/langtools/tools/javac/lambda/MethodReference41.out @@ -1,4 +1,4 @@ -MethodReference41.java:38:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference41.SAM1, @12, kindname.class, MethodReference41, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.String, kindname.class, MethodReference41.Foo, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.String)))) -MethodReference41.java:40:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference41.SAM3, @12, kindname.class, MethodReference41, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference41.Foo, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.Object)))) +MethodReference41.java:38:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference41.SAM1, @12, kindname.class, MethodReference41, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.String, kindname.class, MethodReference41.Foo, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.String))))) +MethodReference41.java:40:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference41.SAM3, @12, kindname.class, MethodReference41, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference41.Foo, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.Object))))) MethodReference41.java:41:9: compiler.err.ref.ambiguous: m4, kindname.method, m4(MethodReference41.SAM2), MethodReference41, kindname.method, m4(MethodReference41.SAM3), MethodReference41 3 errors diff --git a/test/langtools/tools/javac/lambda/MethodReference42.out b/test/langtools/tools/javac/lambda/MethodReference42.out index a22a1032a5a..c514626e0c7 100644 --- a/test/langtools/tools/javac/lambda/MethodReference42.out +++ b/test/langtools/tools/javac/lambda/MethodReference42.out @@ -1,4 +1,4 @@ -MethodReference42.java:38:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference42.SAM1, @12, kindname.class, MethodReference42, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number))) -MethodReference42.java:40:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference42.SAM3, @12, kindname.class, MethodReference42, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.Object, java.lang.Number))) +MethodReference42.java:38:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference42.SAM1, @12, kindname.class, MethodReference42, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Number)))) +MethodReference42.java:40:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference42.SAM3, @12, kindname.class, MethodReference42, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.Object), (compiler.misc.upper.bounds: java.lang.Number)))) MethodReference42.java:41:9: compiler.err.ref.ambiguous: m4, kindname.method, m4(MethodReference42.SAM2), MethodReference42, kindname.method, m4(MethodReference42.SAM3), MethodReference42 3 errors diff --git a/test/langtools/tools/javac/lambda/MethodReference43.out b/test/langtools/tools/javac/lambda/MethodReference43.out index 90fa2ef698e..547ad23f317 100644 --- a/test/langtools/tools/javac/lambda/MethodReference43.out +++ b/test/langtools/tools/javac/lambda/MethodReference43.out @@ -1,5 +1,5 @@ -MethodReference43.java:45:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference43.SAM1, @12, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.String, kindname.class, MethodReference43.Foo, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.String)))) -MethodReference43.java:47:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference43.SAM3, @12, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference43.Foo, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.Object)))) +MethodReference43.java:45:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference43.SAM1, @12, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.String, kindname.class, MethodReference43.Foo, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.String))))) +MethodReference43.java:47:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference43.SAM3, @12, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference43.Foo, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.Object))))) MethodReference43.java:49:9: compiler.err.ref.ambiguous: m5, kindname.method, m5(MethodReference43.SAM3), MethodReference43, kindname.method, m5(MethodReference43.SAM4), MethodReference43 -MethodReference43.java:49:11: compiler.err.cant.apply.symbol: kindname.method, m5, MethodReference43.SAM3, @12, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference43.Foo, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.Object)))) +MethodReference43.java:49:11: compiler.err.cant.apply.symbol: kindname.method, m5, MethodReference43.SAM3, @12, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference43.Foo, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.Object))))) 4 errors diff --git a/test/langtools/tools/javac/lambda/MethodReference44.out b/test/langtools/tools/javac/lambda/MethodReference44.out index 87e1afedbd5..1b7a6dc883f 100644 --- a/test/langtools/tools/javac/lambda/MethodReference44.out +++ b/test/langtools/tools/javac/lambda/MethodReference44.out @@ -1,4 +1,4 @@ -MethodReference44.java:40:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference44.SAM1, @12, kindname.class, MethodReference44, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number))) -MethodReference44.java:42:11: compiler.err.cant.apply.symbol: kindname.method, g3, MethodReference44.SAM3, @12, kindname.class, MethodReference44, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.Object, java.lang.Number))) +MethodReference44.java:40:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference44.SAM1, @12, kindname.class, MethodReference44, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Number)))) +MethodReference44.java:42:11: compiler.err.cant.apply.symbol: kindname.method, g3, MethodReference44.SAM3, @12, kindname.class, MethodReference44, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.Object), (compiler.misc.upper.bounds: java.lang.Number)))) MethodReference44.java:43:9: compiler.err.ref.ambiguous: g4, kindname.method, g4(MethodReference44.SAM2), MethodReference44, kindname.method, g4(MethodReference44.SAM3), MethodReference44 3 errors diff --git a/test/langtools/tools/javac/lambda/MethodReference46.out b/test/langtools/tools/javac/lambda/MethodReference46.out index fe28df29925..3bd3af7e1ae 100644 --- a/test/langtools/tools/javac/lambda/MethodReference46.out +++ b/test/langtools/tools/javac/lambda/MethodReference46.out @@ -1,4 +1,4 @@ -MethodReference46.java:40:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference46.SAM1, @12, kindname.class, MethodReference46, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m, X, java.lang.String, kindname.class, MethodReference46, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.String)))) -MethodReference46.java:42:11: compiler.err.cant.apply.symbol: kindname.method, g3, MethodReference46.SAM3, @12, kindname.class, MethodReference46, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m, X, java.lang.Object, kindname.class, MethodReference46, (compiler.misc.incompatible.upper.lower.bounds: X, java.lang.Number, java.lang.Object)))) +MethodReference46.java:40:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference46.SAM1, @12, kindname.class, MethodReference46, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m, X, java.lang.String, kindname.class, MethodReference46, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.String))))) +MethodReference46.java:42:11: compiler.err.cant.apply.symbol: kindname.method, g3, MethodReference46.SAM3, @12, kindname.class, MethodReference46, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m, X, java.lang.Object, kindname.class, MethodReference46, (compiler.misc.incompatible.bounds: X, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: java.lang.Object))))) MethodReference46.java:43:9: compiler.err.ref.ambiguous: g4, kindname.method, g4(MethodReference46.SAM2), MethodReference46, kindname.method, g4(MethodReference46.SAM3), MethodReference46 3 errors diff --git a/test/langtools/tools/javac/lambda/MethodReference58.out b/test/langtools/tools/javac/lambda/MethodReference58.out index c355b45c3fb..18d0ae74d01 100644 --- a/test/langtools/tools/javac/lambda/MethodReference58.out +++ b/test/langtools/tools/javac/lambda/MethodReference58.out @@ -1,2 +1,2 @@ -MethodReference58.java:41:23: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, g, Z, X, kindname.class, MethodReference58, (compiler.misc.incompatible.upper.lower.bounds: Z, java.lang.Number, X))) +MethodReference58.java:41:23: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, g, Z, X, kindname.class, MethodReference58, (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: java.lang.Number), (compiler.misc.lower.bounds: X)))) 1 error diff --git a/test/langtools/tools/javac/lambda/MethodReference68.out b/test/langtools/tools/javac/lambda/MethodReference68.out index 83ef775ea3b..37d3bbb487b 100644 --- a/test/langtools/tools/javac/lambda/MethodReference68.out +++ b/test/langtools/tools/javac/lambda/MethodReference68.out @@ -1,2 +1,2 @@ -MethodReference68.java:21:10: compiler.err.cant.apply.symbol: kindname.method, g, MethodReference68.F,Z[], @12,int, kindname.class, MethodReference68, (compiler.misc.incompatible.upper.lower.bounds: Z, MethodReference68.Foo,java.lang.Object, java.lang.Integer) -1 error \ No newline at end of file +MethodReference68.java:21:10: compiler.err.cant.apply.symbol: kindname.method, g, MethodReference68.F,Z[], @12,int, kindname.class, MethodReference68, (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: MethodReference68.Foo,java.lang.Object), (compiler.misc.lower.bounds: java.lang.Integer)) +1 error diff --git a/test/langtools/tools/javac/lambda/TargetType02.out b/test/langtools/tools/javac/lambda/TargetType02.out index 9115435a58c..2c40b0ea8ef 100644 --- a/test/langtools/tools/javac/lambda/TargetType02.out +++ b/test/langtools/tools/javac/lambda/TargetType02.out @@ -1,4 +1,4 @@ -TargetType02.java:33:14: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.lower.bounds: Z, java.lang.String, java.lang.Integer) +TargetType02.java:33:14: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: Z, (compiler.misc.upper.bounds: java.lang.String), (compiler.misc.lower.bounds: java.lang.Integer)) TargetType02.java:34:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(TargetType02.S1), TargetType02, kindname.method, call3(TargetType02.S2), TargetType02 TargetType02.java:35:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(TargetType02.S1), TargetType02, kindname.method, call3(TargetType02.S2), TargetType02 TargetType02.java:37:20: compiler.err.ref.ambiguous: call4, kindname.method, call4(TargetType02.S1), TargetType02, kindname.method, call4(TargetType02.S2), TargetType02 diff --git a/test/langtools/tools/javac/lambda/TargetType14.out b/test/langtools/tools/javac/lambda/TargetType14.out index fc031871b98..13958acc3fb 100644 --- a/test/langtools/tools/javac/lambda/TargetType14.out +++ b/test/langtools/tools/javac/lambda/TargetType14.out @@ -1,2 +1,2 @@ -TargetType14.java:20:29: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.lower.bounds: X, java.lang.Integer, java.lang.String) +TargetType14.java:20:29: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.Integer), (compiler.misc.lower.bounds: java.lang.String)) 1 error diff --git a/test/langtools/tools/javac/lambda/TargetType28.out b/test/langtools/tools/javac/lambda/TargetType28.out index 1e2949a8dc8..2850fea5758 100644 --- a/test/langtools/tools/javac/lambda/TargetType28.out +++ b/test/langtools/tools/javac/lambda/TargetType28.out @@ -1,2 +1,2 @@ -TargetType28.java:20:32: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Object,java.lang.Number) +TargetType28.java:20:32: compiler.err.prob.found.req: (compiler.misc.incompatible.bounds: X, (compiler.misc.eq.bounds: java.lang.String), (compiler.misc.upper.bounds: java.lang.Object,java.lang.Number)) 1 error From 839458fd2131d920b4cad54e1027278210caff23 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 24 Apr 2018 09:04:57 -0700 Subject: [PATCH 028/102] 8199755: Update Graal Reviewed-by: kvn --- make/CompileJavaModules.gmk | 2 +- make/CompileToolsHotspot.gmk | 10 +- .../jdk/tools/jaotc/AOTCompilationTask.java | 10 +- .../src/jdk/tools/jaotc/GraalFilters.java | 2 +- .../src/jdk/tools/jaotc/Main.java | 2 +- .../management/HotSpotGraalManagement.java | 150 +++++- .../management/HotSpotGraalRuntimeMBean.java | 234 +++++++++ .../management/JMXServiceProvider.java | 67 +++ .../hotspot/management/package-info.java | 29 ++ .../collections/test/EconomicMapImplTest.java | 10 +- .../test/EconomicMapLargeTest.java | 10 +- .../collections/test/EconomicMapTest.java | 6 +- .../collections/test/EconomicSetTest.java | 6 +- .../collections/test/EquivalenceTest.java | 4 +- .../compiler}/collections/test/PairTest.java | 4 +- .../vm/compiler}/collections/EconomicMap.java | 2 +- .../collections/EconomicMapImpl.java | 2 +- .../vm/compiler}/collections/EconomicSet.java | 2 +- .../vm/compiler}/collections/Equivalence.java | 2 +- .../vm/compiler}/collections/MapCursor.java | 2 +- .../vm/compiler}/collections/Pair.java | 2 +- .../collections/UnmodifiableEconomicMap.java | 2 +- .../collections/UnmodifiableEconomicSet.java | 2 +- .../collections/UnmodifiableMapCursor.java | 2 +- .../compiler}/collections/package-info.java | 11 +- .../vm/compiler}/word/ComparableWord.java | 11 +- .../vm/compiler}/word/LocationIdentity.java | 62 ++- .../internal/vm/compiler}/word/Pointer.java | 452 +++++++++++++++++- .../vm/compiler}/word/PointerBase.java | 8 +- .../vm/compiler}/word/SignedWord.java | 73 ++- .../vm/compiler}/word/UnsignedWord.java | 73 ++- .../internal/vm/compiler}/word/WordBase.java | 14 +- .../vm/compiler}/word/WordFactory.java | 88 ++-- .../vm/compiler/word/impl/WordBoxFactory.java | 42 ++ .../compiler/word/impl/WordFactoryOpcode.java | 34 ++ .../word/impl/WordFactoryOperation.java | 39 ++ .../vm/compiler/word/package-info.java | 36 ++ .../share/classes/module-info.java | 20 +- .../aarch64/test/TestProtectedAssembler.java | 4 +- .../asm/aarch64/AArch64Assembler.java | 35 +- .../compiler/code/CompilationResult.java | 2 +- .../SourceStackTraceBailoutException.java | 8 +- .../core/aarch64/AArch64LIRGenerator.java | 19 +- .../core}/aarch64/AArch64ReadNode.java | 7 +- .../aarch64/AArch64ReadReplacementPhase.java | 6 +- .../core/aarch64/AArch64SuitesCreator.java | 25 +- .../core/amd64/AMD64MoveFactoryBase.java | 4 +- .../compiler/core/common/GraalOptions.java | 8 +- .../common/PermanentBailoutException.java | 2 +- .../alloc/RegisterAllocationConfig.java | 4 +- .../common/doc-files/TraceInliningHelp.txt | 8 + .../core/common/spi/ForeignCallsProvider.java | 2 +- .../core/common/util/FrequencyEncoder.java | 4 +- .../compiler/core/common/util/ModuleAPI.java | 126 ----- .../core/match/processor/MatchProcessor.java | 6 +- .../core/test/CheckGraalInvariants.java | 14 +- .../compiler/core/test/DumpPathTest.java | 2 +- .../core/test/GraphResetDebugTest.java | 2 +- .../core/test/InfopointReasonTest.java | 8 +- .../core/test/MarkUnsafeAccessTest.java | 3 +- .../core/test/ReferenceGetLoopTest.java | 2 +- .../test/ReflectionOptionDescriptors.java | 9 +- .../core/test/StampMemoryAccessTest.java | 15 +- .../core/test/ea/EscapeAnalysisTest.java | 3 + .../core/test/inlining/InliningTest.java | 48 +- .../NestedLoopEffectsPhaseComplexityTest.java | 5 +- .../compiler/core/CompilationPrinter.java | 32 +- .../compiler/core/CompilationWrapper.java | 36 +- .../graalvm/compiler/core/GraalCompiler.java | 24 +- .../compiler/core/GraalCompilerOptions.java | 6 +- .../compiler/core/gen/DebugInfoBuilder.java | 4 +- .../compiler/core/gen/NodeLIRBuilder.java | 4 +- .../compiler/core/match/MatchContext.java | 4 +- .../core/match/MatchRuleRegistry.java | 6 +- ...va => CommunityCompilerConfiguration.java} | 5 +- .../phases/EconomyCompilerConfiguration.java | 4 + .../phases/GraphChangeMonitoringPhase.java | 4 +- .../graalvm/compiler/core/target/Backend.java | 5 +- .../compiler/debug/test/DebugContextTest.java | 2 +- .../compiler/debug/test/TimerKeyTest.java | 18 +- .../compiler/debug/CounterKeyImpl.java | 2 +- .../compiler/debug/DebugConfigImpl.java | 3 +- .../graalvm/compiler/debug/DebugContext.java | 24 +- .../graalvm/compiler/debug/DebugOptions.java | 28 +- .../debug/DiagnosticsOutputDirectory.java | 23 +- .../graalvm/compiler/debug/GlobalMetrics.java | 6 +- .../graalvm/compiler/debug/KeyRegistry.java | 2 +- .../graalvm/compiler/debug/Management.java | 226 --------- .../compiler/debug/MemUseTrackerKey.java | 4 +- .../compiler/debug/MemUseTrackerKeyImpl.java | 2 +- .../org/graalvm/compiler/debug/MetricKey.java | 2 +- .../graalvm/compiler/debug/PathUtilities.java | 14 - .../graalvm/compiler/debug/TimeSource.java | 16 +- .../graalvm/compiler/debug/TimerKeyImpl.java | 2 +- .../.checkstyle_checks.xml | 241 ---------- .../graalvm/compiler/graph/CachedGraph.java | 2 +- .../src/org/graalvm/compiler/graph/Graph.java | 35 +- .../src/org/graalvm/compiler/graph/Node.java | 132 ++++- .../org/graalvm/compiler/graph/NodeClass.java | 4 +- .../org/graalvm/compiler/graph/NodeMap.java | 4 +- .../compiler/graph/NodeSourcePosition.java | 23 +- .../graph/SourceLanguagePosition.java | 24 +- .../aarch64/AArch64HotSpotBackend.java | 2 +- .../aarch64/AArch64HotSpotBackendFactory.java | 16 +- .../AArch64HotSpotForeignCallsProvider.java | 2 +- ...tSpotJumpToExceptionHandlerInCallerOp.java | 6 +- ...Arch64HotSpotRegisterAllocationConfig.java | 3 +- .../aarch64/AArch64HotSpotSuitesProvider.java | 70 --- .../amd64/AMD64HotSpotAddressLowering.java | 2 +- .../hotspot/amd64/AMD64HotSpotBackend.java | 2 +- .../amd64/AMD64HotSpotBackendFactory.java | 5 +- .../AMD64HotSpotForeignCallsProvider.java | 2 +- ...tSpotJumpToExceptionHandlerInCallerOp.java | 3 +- .../hotspot/sparc/SPARCHotSpotBackend.java | 6 +- .../sparc/SPARCHotSpotBackendFactory.java | 5 +- .../SPARCHotSpotForeignCallsProvider.java | 2 +- .../hotspot/test/CheckGraalIntrinsics.java | 10 +- .../hotspot/test/CompilationWrapperTest.java | 20 +- .../hotspot/test/CompileTheWorld.java | 42 +- .../hotspot/test/CompileTheWorldTest.java | 2 +- .../hotspot/test/GraalOSRLockTest.java | 13 +- .../compiler/hotspot/test/GraalOSRTest.java | 56 +++ .../hotspot/test/GraalOSRTestBase.java | 24 +- .../hotspot/test/HotSpotGraalMBeanTest.java | 241 ---------- .../test/HotSpotGraalManagementTest.java | 407 ++++++++++++++++ .../test/HotSpotMethodSubstitutionTest.java | 21 + .../test/HotSpotStampMemoryAccessTest.java | 2 - .../hotspot/test/TestIntrinsicCompiles.java | 2 +- .../test/WriteBarrierVerificationTest.java | 4 +- .../src/org/graalvm/compiler/hotspot/test/aaa | 78 +++ ...ommunityCompilerConfigurationFactory.java} | 17 +- .../hotspot/CompilationStatistics.java | 5 +- .../compiler/hotspot/CompilationTask.java | 31 +- .../hotspot/CompilerConfigurationFactory.java | 2 +- .../EconomyCompilerConfigurationFactory.java | 7 +- .../hotspot/GraalHotSpotVMConfig.java | 141 ++---- .../hotspot/GraalHotSpotVMConfigBase.java | 100 ++++ .../GraalHotSpotVMConfigVersioned.java | 82 ++++ .../compiler/hotspot/HotSpotBackend.java | 10 +- .../hotspot/HotSpotCompiledCodeBuilder.java | 4 + .../compiler/hotspot/HotSpotCounterOp.java | 2 +- .../hotspot/HotSpotForeignCallLinkage.java | 2 +- .../HotSpotForeignCallLinkageImpl.java | 4 +- .../hotspot/HotSpotGraalCompiler.java | 14 +- .../hotspot/HotSpotGraalCompilerFactory.java | 92 +--- .../compiler/hotspot/HotSpotGraalMBean.java | 362 -------------- .../HotSpotGraalManagementRegistration.java | 49 ++ .../hotspot/HotSpotGraalOptionValues.java | 12 +- .../compiler/hotspot/HotSpotGraalRuntime.java | 290 +++++++++-- .../hotspot/HotSpotGraalRuntimeProvider.java | 11 +- .../hotspot/HotSpotLIRGenerationResult.java | 4 +- .../compiler/hotspot/IsGraalPredicate.java | 61 +++ .../hotspot/PrintStreamOptionKey.java | 44 +- .../compiler/hotspot/WeakClassLoaderSet.java | 118 +++++ .../AddressLoweringHotSpotSuitesProvider.java | 8 +- .../meta/DefaultHotSpotLoweringProvider.java | 4 +- .../meta/HotSpotForeignCallsProviderImpl.java | 4 +- .../meta/HotSpotGraphBuilderPlugins.java | 17 +- .../meta/HotSpotHostForeignCallsProvider.java | 11 +- .../meta/HotSpotInvocationPlugins.java | 89 +--- .../meta/HotSpotUnsafeSubstitutions.java | 6 +- .../meta/HotSpotWordOperationPlugin.java | 4 +- .../meta/IntrinsificationPredicate.java | 66 +++ .../hotspot/nodes/BeginLockScopeNode.java | 2 +- .../hotspot/nodes/EndLockScopeNode.java | 2 +- .../hotspot/nodes/StubForeignCallNode.java | 2 +- .../nodes/aot/InitializeKlassNode.java | 2 +- .../nodes/aot/InitializeKlassStubCall.java | 2 +- .../nodes/aot/ResolveDynamicConstantNode.java | 2 +- .../nodes/aot/ResolveDynamicStubCall.java | 2 +- .../phases/OnStackReplacementPhase.java | 136 +++--- .../phases/WriteBarrierAdditionPhase.java | 30 +- .../hotspot/phases/aot/AOTInliningPolicy.java | 20 +- ...EliminateRedundantInitializationPhase.java | 2 +- .../phases/aot/ReplaceConstantNodesPhase.java | 2 +- .../replacements/AESCryptSubstitutions.java | 6 +- .../replacements/CRC32CSubstitutions.java | 4 +- .../replacements/CRC32Substitutions.java | 6 +- .../CipherBlockChainingSubstitutions.java | 6 +- .../hotspot/replacements/ClassGetHubNode.java | 2 +- .../replacements/HashCodeSnippets.java | 2 +- .../replacements/HotSpotReplacementsUtil.java | 4 +- .../replacements/IdentityHashCodeNode.java | 2 +- .../LoadExceptionObjectSnippets.java | 2 +- .../hotspot/replacements/MonitorSnippets.java | 8 +- .../replacements/NewObjectSnippets.java | 4 +- .../replacements/ObjectSubstitutions.java | 22 + .../replacements/SHA2Substitutions.java | 6 +- .../replacements/SHA5Substitutions.java | 6 +- .../replacements/SHASubstitutions.java | 6 +- .../replacements/StringToBytesSnippets.java | 2 +- .../replacements/ThreadSubstitutions.java | 2 +- .../replacements/WriteBarrierSnippets.java | 8 +- .../arraycopy/ArrayCopyCallNode.java | 2 +- .../replacements/arraycopy/ArrayCopyNode.java | 4 +- .../arraycopy/ArrayCopySnippets.java | 6 +- .../arraycopy/CheckcastArrayCopyCallNode.java | 2 +- .../arraycopy/GenericArrayCopyCallNode.java | 2 +- .../hotspot/stubs/CreateExceptionStub.java | 2 +- .../hotspot/stubs/ExceptionHandlerStub.java | 2 +- .../hotspot/stubs/ForeignCallStub.java | 43 +- .../compiler/hotspot/stubs/NewArrayStub.java | 2 +- .../hotspot/stubs/NewInstanceStub.java | 2 +- .../graalvm/compiler/hotspot/stubs/Stub.java | 5 +- .../compiler/hotspot/stubs/StubUtil.java | 4 +- .../stubs/UnwindExceptionToCallerStub.java | 2 +- .../compiler/hotspot/word/KlassPointer.java | 4 +- .../hotspot/word/MetaspacePointer.java | 10 +- .../compiler/hotspot/word/MethodPointer.java | 2 +- .../compiler/java/BciBlockMapping.java | 191 +++++--- .../graalvm/compiler/java/BytecodeParser.java | 254 ++++++---- .../compiler/java/BytecodeParserOptions.java | 6 +- .../java/ComputeLoopFrequenciesClosure.java | 2 +- .../compiler/java/FrameStateBuilder.java | 13 - .../graalvm/compiler/java/LocalLiveness.java | 2 +- .../lir/aarch64/AArch64ArrayCompareToOp.java | 286 +++++++++++ .../lir/aarch64/AArch64AtomicMove.java | 102 ++++ .../compiler/lir/aarch64/AArch64Move.java | 56 --- .../lir/amd64/AMD64ArrayCompareToOp.java | 12 +- .../lir/amd64/AMD64SaveRegistersOp.java | 2 +- .../lir/amd64/AMD64ZapRegistersOp.java | 2 +- .../compiler/lir/sparc/SPARCControlFlow.java | 4 +- .../lir/sparc/SPARCSaveRegistersOp.java | 2 +- .../TraceGlobalMoveResolutionMappingTest.java | 2 +- .../compiler/lir/LIRIntrospection.java | 6 +- .../lir/RedundantMoveElimination.java | 4 +- .../org/graalvm/compiler/lir/StandardOp.java | 2 +- .../lir/alloc/RegisterAllocationPhase.java} | 26 +- .../compiler/lir/alloc/lsra/LinearScan.java | 2 +- .../lsra/LinearScanLifetimeAnalysisPhase.java | 72 +-- .../lir/alloc/lsra/LinearScanPhase.java | 12 +- .../LinearScanRegisterAllocationPhase.java | 2 +- .../compiler/lir/alloc/lsra/MoveResolver.java | 4 +- .../trace/TraceRegisterAllocationPhase.java | 19 +- .../lir/asm/CompilationResultBuilder.java | 4 +- .../compiler/lir/gen/LIRGenerationResult.java | 4 +- .../graalvm/compiler/lir/gen/PhiResolver.java | 4 +- .../compiler/lir/phases/AllocationStage.java | 4 - .../lir/phases/EconomyAllocationStage.java | 4 - .../FixPointIntervalBuilder.java | 4 +- .../stackslotalloc/LSStackSlotAllocator.java | 2 +- .../compiler/lir/util/GenericValueMap.java | 4 +- .../compiler/loop/CountedLoopInfo.java | 46 +- .../src/org/graalvm/compiler/loop/LoopEx.java | 6 +- .../graalvm/compiler/loop/LoopFragment.java | 2 +- .../compiler/loop/LoopFragmentInside.java | 4 +- .../compiler/loop/LoopFragmentWhole.java | 2 +- .../org/graalvm/compiler/loop/LoopsData.java | 6 +- .../graalvm/compiler/nodes/EncodedGraph.java | 2 +- .../compiler/nodes/FieldLocationIdentity.java | 2 +- .../graalvm/compiler/nodes/GraphDecoder.java | 6 +- .../graalvm/compiler/nodes/GraphEncoder.java | 4 +- .../compiler/nodes/GraphSpeculationLog.java | 123 +++++ .../org/graalvm/compiler/nodes/IfNode.java | 4 +- .../graalvm/compiler/nodes/InliningLog.java | 186 +++++-- .../org/graalvm/compiler/nodes/Invokable.java | 4 + .../graalvm/compiler/nodes/InvokeNode.java | 2 +- .../nodes/InvokeWithExceptionNode.java | 2 +- .../compiler/nodes/KillingBeginNode.java | 2 +- .../graalvm/compiler/nodes/LoopExitNode.java | 4 +- .../compiler/nodes/NamedLocationIdentity.java | 6 +- .../org/graalvm/compiler/nodes/StartNode.java | 2 +- .../compiler/nodes/StructuredGraph.java | 22 +- .../org/graalvm/compiler/nodes/cfg/Block.java | 2 +- .../graalvm/compiler/nodes/cfg/HIRLoop.java | 2 +- .../compiler/nodes/cfg/LocationSet.java | 2 +- .../nodes/debug/StringToBytesNode.java | 2 +- .../nodes/extended/BytecodeExceptionNode.java | 2 +- .../nodes/extended/ForeignCallNode.java | 2 +- .../nodes/extended/GuardedUnsafeLoadNode.java | 2 +- .../compiler/nodes/extended/JavaReadNode.java | 2 +- .../nodes/extended/JavaWriteNode.java | 2 +- .../compiler/nodes/extended/MembarNode.java | 2 +- .../compiler/nodes/extended/RawLoadNode.java | 2 +- .../compiler/nodes/extended/RawStoreNode.java | 2 +- .../nodes/extended/UnsafeAccessNode.java | 2 +- .../nodes/extended/UnsafeCopyNode.java | 2 +- .../nodes/extended/UnsafeMemoryLoadNode.java | 2 +- .../nodes/extended/UnsafeMemoryStoreNode.java | 2 +- .../graphbuilderconf/InvocationPlugins.java | 14 +- .../java/AbstractCompareAndSwapNode.java | 2 +- .../nodes/java/AtomicReadAndAddNode.java | 2 +- .../nodes/java/AtomicReadAndWriteNode.java | 2 +- .../nodes/java/ExceptionObjectNode.java | 2 +- .../nodes/java/LogicCompareAndSwapNode.java | 2 +- .../java/LoweredAtomicReadAndWriteNode.java | 2 +- .../compiler/nodes/java/MonitorEnterNode.java | 2 +- .../compiler/nodes/java/MonitorExitNode.java | 2 +- .../nodes/java/RawMonitorEnterNode.java | 2 +- .../nodes/java/UnsafeCompareAndSwapNode.java | 6 +- .../nodes/java/ValueCompareAndSwapNode.java | 2 +- .../nodes/memory/AbstractWriteNode.java | 2 +- .../graalvm/compiler/nodes/memory/Access.java | 2 +- .../nodes/memory/FixedAccessNode.java | 2 +- .../nodes/memory/FloatableAccessNode.java | 2 +- .../nodes/memory/FloatingAccessNode.java | 2 +- .../nodes/memory/FloatingReadNode.java | 2 +- .../compiler/nodes/memory/MemoryAccess.java | 2 +- .../nodes/memory/MemoryCheckpoint.java | 2 +- .../compiler/nodes/memory/MemoryMap.java | 2 +- .../compiler/nodes/memory/MemoryMapNode.java | 10 +- .../compiler/nodes/memory/MemoryPhiNode.java | 2 +- .../compiler/nodes/memory/ReadNode.java | 2 +- .../compiler/nodes/memory/WriteNode.java | 2 +- .../compiler/nodes/spi/MemoryProxy.java | 2 +- .../compiler/nodes/util/GraphUtil.java | 8 +- .../nodes/virtual/CommitAllocationNode.java | 2 +- .../options/processor/OptionProcessor.java | 12 +- .../test/NestedBooleanOptionKeyTest.java | 13 +- .../compiler/options/test/TestOptionKey.java | 3 +- .../compiler/options/EnumOptionKey.java | 6 +- .../options/ModifiableOptionValues.java | 8 +- .../compiler/options/OptionDescriptor.java | 32 +- .../graalvm/compiler/options/OptionKey.java | 2 +- .../compiler/options/OptionValues.java | 12 +- .../compiler/options/OptionsParser.java | 8 +- .../common/AddressLoweringByUsePhase.java | 2 +- .../phases/common/CanonicalizerPhase.java | 4 +- .../common/ConditionalEliminationPhase.java | 8 +- .../phases/common/ExpandLogicPhase.java | 140 +++--- .../compiler/phases/common/FixReadsPhase.java | 4 +- .../phases/common/FloatingReadPhase.java | 12 +- .../common/FrameStateAssignmentPhase.java | 2 +- .../compiler/phases/common/LoweringPhase.java | 2 +- .../PropagateDeoptimizeProbabilityPhase.java | 6 +- .../phases/common/inlining/InliningUtil.java | 127 +++-- .../inlining/info/AbstractInlineInfo.java | 6 +- .../inlining/info/AssumptionInlineInfo.java | 6 +- .../common/inlining/info/ExactInlineInfo.java | 6 +- .../common/inlining/info/InlineInfo.java | 4 +- .../info/MultiTypeGuardInlineInfo.java | 22 +- .../inlining/info/TypeGuardInlineInfo.java | 28 +- .../inlining/policy/GreedyInliningPolicy.java | 24 +- .../policy/InlineEverythingPolicy.java | 5 +- .../InlineMethodSubstitutionsPolicy.java | 8 +- .../inlining/policy/InliningPolicy.java | 30 +- .../walker/CallsiteHolderExplorable.java | 4 +- .../walker/ComputeInliningRelevance.java | 4 +- .../common/inlining/walker/InliningData.java | 32 +- .../common/util/HashSetNodeEventListener.java | 4 +- .../graph/FixedNodeProbabilityCache.java | 4 +- .../phases/graph/PostOrderNodeIterator.java | 4 +- .../phases/graph/ReentrantBlockIterator.java | 4 +- .../phases/graph/ReentrantNodeIterator.java | 6 +- .../phases/graph/SinglePassNodeIterator.java | 4 +- .../schedule/MemoryScheduleVerification.java | 6 +- .../phases/schedule/SchedulePhase.java | 6 +- .../graalvm/compiler/phases/tiers/Suites.java | 24 +- .../compiler/phases/util/GraphOrder.java | 4 +- .../verify/VerifyCallerSensitiveMethods.java | 2 +- .../phases/verify/VerifyGraphAddUsage.java | 2 +- .../compiler/printer/BinaryGraphPrinter.java | 104 +++- .../graalvm/compiler/printer/CFGPrinter.java | 22 +- .../compiler/printer/GraphPrinter.java | 27 +- .../printer/GraphPrinterDumpHandler.java | 9 +- .../aarch64/AArch64GraphBuilderPlugins.java | 23 + .../AArch64StringLatin1Substitutions.java | 59 +++ .../AArch64StringUTF16Substitutions.java | 63 +++ .../amd64/AMD64GraphBuilderPlugins.java | 9 +- .../amd64/AMD64StringIndexOfNode.java | 4 +- .../amd64/AMD64StringSubstitutions.java | 2 +- .../test/NestedExceptionHandlerTest.java | 71 +++ .../replacements/test/ObjectAccessTest.java | 6 +- .../replacements/test/PEGraphDecoderTest.java | 2 +- .../replacements/test/PointerTest.java | 6 +- .../test/ReplacementsParseTest.java | 2 +- .../test/StringCompareToTest.java | 26 +- .../compiler/replacements/test/WordTest.java | 8 +- .../ClassfileBytecodeProviderTest.java | 2 +- .../replacements/CachingPEGraphDecoder.java | 2 +- .../DefaultJavaLoweringProvider.java | 34 +- .../compiler/replacements/GraphKit.java | 61 ++- .../replacements/MethodHandlePlugin.java | 24 +- .../compiler/replacements/PEGraphDecoder.java | 4 +- .../replacements/ReplacementsImpl.java | 4 +- .../replacements/SnippetCounterNode.java | 2 +- .../SnippetLowerableMemoryNode.java | 2 +- .../replacements/SnippetTemplate.java | 23 +- .../StandardGraphBuilderPlugins.java | 36 +- .../classfile/ClassfileBytecodeProvider.java | 25 +- .../graalvm/compiler/replacements/classfile/D | 102 ++++ .../nodes/ArrayCompareToNode.java | 2 +- .../replacements/nodes/ArrayEqualsNode.java | 2 +- .../nodes/BasicArrayCopyNode.java | 4 +- .../replacements/nodes/MacroNode.java | 2 +- .../nodes/MacroStateSplitNode.java | 2 +- .../serviceprovider/GraalServices.java | 264 ++++++++-- .../compiler/serviceprovider/JDK9Method.java | 153 ------ .../org/graalvm/compiler/test/GraalTest.java | 3 +- .../graalvm/compiler/test/SubprocessUtil.java | 3 +- .../.checkstyle.exclude | 1 - .../virtual/phases/ea/EffectsBlockState.java | 4 +- .../virtual/phases/ea/EffectsClosure.java | 8 +- .../virtual/phases/ea/EffectsPhase.java | 2 +- .../ea/PEReadEliminationBlockState.java | 6 +- .../phases/ea/PEReadEliminationClosure.java | 12 +- .../phases/ea/PartialEscapeClosure.java | 6 +- .../virtual/phases/ea/PartialEscapePhase.java | 2 +- .../phases/ea/ReadEliminationBlockState.java | 6 +- .../phases/ea/ReadEliminationClosure.java | 12 +- .../virtual/phases/ea/VirtualUtil.java | 4 +- .../compiler/word/BarrieredAccess.java | 10 +- .../graalvm/compiler/word/ObjectAccess.java | 10 +- .../src/org/graalvm/compiler/word/Word.java | 121 ++--- .../compiler/word/WordOperationPlugin.java | 26 +- .../org/graalvm/compiler/word/WordTypes.java | 4 +- .../org/graalvm/graphio/GraphElements.java | 6 +- .../org/graalvm/graphio/GraphLocations.java | 117 +++++ .../src/org/graalvm/graphio/GraphOutput.java | 111 ++++- .../org/graalvm/graphio/GraphProtocol.java | 294 ++++++++---- .../src/org/graalvm/graphio/ProtocolImpl.java | 71 ++- .../graalvm/util/test/CollectionSizeTest.java | 4 +- .../org/graalvm/util/ObjectSizeEstimate.java | 4 +- .../org.graalvm.word/.checkstyle_checks.xml | 240 ---------- 414 files changed, 6724 insertions(+), 3876 deletions(-) create mode 100644 src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.java create mode 100644 src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/JMXServiceProvider.java create mode 100644 src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/package-info.java rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections.test/src/org/graalvm => jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler}/collections/test/EconomicMapImplTest.java (93%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections.test/src/org/graalvm => jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler}/collections/test/EconomicMapLargeTest.java (96%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections.test/src/org/graalvm => jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler}/collections/test/EconomicMapTest.java (93%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections.test/src/org/graalvm => jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler}/collections/test/EconomicSetTest.java (96%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections.test/src/org/graalvm => jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler}/collections/test/EquivalenceTest.java (96%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections.test/src/org/graalvm => jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler}/collections/test/PairTest.java (95%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/EconomicMap.java (99%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/EconomicMapImpl.java (99%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/EconomicSet.java (99%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/Equivalence.java (98%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/MapCursor.java (97%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/Pair.java (98%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/UnmodifiableEconomicMap.java (98%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/UnmodifiableEconomicSet.java (98%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/UnmodifiableMapCursor.java (97%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.collections/src/org/graalvm => jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler}/collections/package-info.java (86%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/ComparableWord.java (90%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/LocationIdentity.java (70%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/Pointer.java (73%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/PointerBase.java (94%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/SignedWord.java (90%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/UnsignedWord.java (92%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/WordBase.java (86%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.word/src/org/graalvm => jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler}/word/WordFactory.java (67%) create mode 100644 src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements => org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core}/aarch64/AArch64ReadNode.java (95%) rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements => org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core}/aarch64/AArch64ReadReplacementPhase.java (92%) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/doc-files/TraceInliningHelp.txt delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java rename src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/{CoreCompilerConfiguration.java => CommunityCompilerConfiguration.java} (95%) delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa rename src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/{CoreCompilerConfigurationFactory.java => CommunityCompilerConfigurationFactory.java} (70%) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalManagementRegistration.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/WeakClassLoaderSet.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/IntrinsificationPredicate.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AtomicMove.java rename src/jdk.internal.vm.compiler/share/classes/{org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValuesAccess.java => org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/RegisterAllocationPhase.java} (64%) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphSpeculationLog.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringLatin1Substitutions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringUTF16Substitutions.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/D delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphLocations.java delete mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 9d1d6cb7618..4f33b17247a 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -439,7 +439,7 @@ jdk.internal.vm.compiler_ADD_JAVAC_FLAGS += -parameters -XDstringConcat=inline \ # jdk.internal.vm.compiler_EXCLUDES += \ - org.graalvm.collections.test \ + jdk.internal.vm.compiler.collections.test \ org.graalvm.compiler.core.match.processor \ org.graalvm.compiler.nodeinfo.processor \ org.graalvm.compiler.options.processor \ diff --git a/make/CompileToolsHotspot.gmk b/make/CompileToolsHotspot.gmk index 79468ad62b2..f0eb30cbd1d 100644 --- a/make/CompileToolsHotspot.gmk +++ b/make/CompileToolsHotspot.gmk @@ -47,8 +47,8 @@ ifeq ($(INCLUDE_GRAAL), true) $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := \ - $(SRC_DIR)/org.graalvm.word/src \ - $(SRC_DIR)/org.graalvm.collections/src \ + $(SRC_DIR)/jdk.internal.vm.compiler.word/src \ + $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \ $(SRC_DIR)/org.graalvm.compiler.core/src \ $(SRC_DIR)/org.graalvm.compiler.core.common/src \ $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \ @@ -102,7 +102,7 @@ ifeq ($(INCLUDE_GRAAL), true) $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := \ - $(SRC_DIR)/org.graalvm.collections/src \ + $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \ $(SRC_DIR)/org.graalvm.compiler.options/src \ $(SRC_DIR)/org.graalvm.compiler.options.processor/src \ $(SRC_DIR)/org.graalvm.util/src \ @@ -118,8 +118,8 @@ ifeq ($(INCLUDE_GRAAL), true) $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := \ - $(SRC_DIR)/org.graalvm.word/src \ - $(SRC_DIR)/org.graalvm.collections/src \ + $(SRC_DIR)/jdk.internal.vm.compiler.word/src \ + $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \ $(SRC_DIR)/org.graalvm.compiler.bytecode/src \ $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \ $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \ diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java index 999e37e879e..4b8785fb0f3 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java @@ -30,11 +30,11 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.GraalCompilerOptions; import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.debug.Management; import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.debug.DebugContext.Activation; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -52,8 +52,6 @@ final class AOTCompilationTask implements Runnable, Comparable { private static final AtomicInteger ids = new AtomicInteger(); - private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean(); - private final Main main; private OptionValues graalOptions; @@ -99,7 +97,7 @@ final class AOTCompilationTask implements Runnable, Comparable { final long threadId = Thread.currentThread().getId(); - final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed(); + final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed() && GraalServices.isThreadAllocatedMemorySupported(); if (printCompilation) { TTY.println(getMethodDescription() + "..."); } @@ -108,7 +106,7 @@ final class AOTCompilationTask implements Runnable, Comparable { final long allocatedBytesBefore; if (printCompilation) { start = System.currentTimeMillis(); - allocatedBytesBefore = printCompilation ? threadMXBean.getThreadAllocatedBytes(threadId) : 0L; + allocatedBytesBefore = GraalServices.getThreadAllocatedBytes(threadId); } else { start = 0L; allocatedBytesBefore = 0L; @@ -125,7 +123,7 @@ final class AOTCompilationTask implements Runnable, Comparable { if (printCompilation) { final long stop = System.currentTimeMillis(); final int targetCodeSize = compResult != null ? compResult.getTargetCodeSize() : -1; - final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId); + final long allocatedBytesAfter = GraalServices.getThreadAllocatedBytes(threadId); final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes)); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java index 010f06b0f0d..7920faaba13 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java @@ -45,7 +45,7 @@ import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions; import org.graalvm.compiler.hotspot.word.MetaspacePointer; import org.graalvm.compiler.replacements.Snippets; -import org.graalvm.word.WordBase; +import jdk.internal.vm.compiler.word.WordBase; final class GraalFilters { private List specialClasses; diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index 14276da09d3..0d3783d1e2b 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -141,7 +141,7 @@ public final class Main { graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered); } graalOptions = new OptionValues(graalOptions, GeneratePIC, true, ImmutableCode, true); - GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler(JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions)); + GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler("JAOTC", JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions)); HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime(); HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend(); MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java index d4176d18e48..5f6cf2582a2 100644 --- a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java +++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java @@ -22,8 +22,154 @@ */ package org.graalvm.compiler.hotspot.management; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.hotspot.HotSpotGraalManagementRegistration; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntime; +import org.graalvm.compiler.serviceprovider.ServiceProvider; + /** - * Placeholder until next Graal update. + * Dynamically registers an MBean with the {@link ManagementFactory#getPlatformMBeanServer()}. + * + * Polling for an active platform MBean server is done by calling + * {@link MBeanServerFactory#findMBeanServer(String)} with an argument value of {@code null}. Once + * this returns an non-empty list, {@link ManagementFactory#getPlatformMBeanServer()} can be called + * to obtain a reference to the platform MBean server instance. */ -public final class HotSpotGraalManagement { +@ServiceProvider(HotSpotGraalManagementRegistration.class) +public final class HotSpotGraalManagement implements HotSpotGraalManagementRegistration { + + private HotSpotGraalRuntimeMBean bean; + private volatile boolean needsRegistration = true; + HotSpotGraalManagement nextDeferred; + + @Override + public void initialize(HotSpotGraalRuntime runtime) { + if (bean == null) { + if (runtime.getManagement() != this) { + throw new IllegalArgumentException("Cannot initialize a second management object for runtime " + runtime.getName()); + } + try { + String name = runtime.getName().replace(':', '_'); + ObjectName objectName = new ObjectName("org.graalvm.compiler.hotspot:type=" + name); + bean = new HotSpotGraalRuntimeMBean(objectName, runtime); + registration.add(this); + } catch (MalformedObjectNameException err) { + err.printStackTrace(TTY.out); + } + } else if (bean.getRuntime() != runtime) { + throw new IllegalArgumentException("Cannot change the runtime a management interface is associated with"); + } + } + + static final class RegistrationThread extends Thread { + + private MBeanServer platformMBeanServer; + private HotSpotGraalManagement deferred; + + RegistrationThread() { + super("HotSpotGraalManagement Bean Registration"); + this.setPriority(Thread.MIN_PRIORITY); + this.setDaemon(true); + this.start(); + } + + /** + * Poll for active MBean server every 2 seconds. + */ + private static final int POLL_INTERVAL_MS = 2000; + + /** + * Adds a {@link HotSpotGraalManagement} to register with an active MBean server when one + * becomes available. + */ + synchronized void add(HotSpotGraalManagement e) { + if (deferred != null) { + e.nextDeferred = deferred; + } + deferred = e; + + // Notify the registration thread that there is now + // a deferred registration to process + notify(); + } + + /** + * Processes and clears any deferred registrations. + */ + private void process() { + for (HotSpotGraalManagement m = deferred; m != null; m = m.nextDeferred) { + HotSpotGraalRuntimeMBean bean = m.bean; + if (m.needsRegistration && bean != null) { + try { + platformMBeanServer.registerMBean(bean, bean.getObjectName()); + } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { + e.printStackTrace(TTY.out); + // Registration failed - don't try again + m.bean = null; + } + m.needsRegistration = false; + } + } + deferred = null; + } + + @Override + public void run() { + while (true) { + try { + synchronized (this) { + // Wait until there are deferred registrations to process + while (deferred == null) { + wait(); + } + } + poll(); + Thread.sleep(POLL_INTERVAL_MS); + } catch (InterruptedException e) { + // Be verbose about unexpected interruption and then continue + e.printStackTrace(TTY.out); + } + } + } + + /** + * Checks for active MBean server and if available, processes deferred registrations. + */ + synchronized void poll() { + if (platformMBeanServer == null) { + ArrayList servers = MBeanServerFactory.findMBeanServer(null); + if (!servers.isEmpty()) { + platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); + process(); + } + } else { + process(); + } + } + } + + private static final RegistrationThread registration = new RegistrationThread(); + + @Override + public ObjectName poll(boolean sync) { + if (sync) { + registration.poll(); + } + if (bean == null || needsRegistration) { + // initialize() has not been called, it failed or registration failed + return null; + } + return bean.getObjectName(); + } } diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.java b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.java new file mode 100644 index 00000000000..23761f3e0de --- /dev/null +++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.management; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +import jdk.internal.vm.compiler.collections.EconomicMap; +import org.graalvm.compiler.core.common.SuppressFBWarnings; +import org.graalvm.compiler.debug.TTY; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntime; +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionsParser; + +/** + * MBean used to access properties and operations of a {@link HotSpotGraalRuntime} instance. + */ +final class HotSpotGraalRuntimeMBean implements DynamicMBean { + + /** + * The runtime instance to which this bean provides a management connection. + */ + private final HotSpotGraalRuntime runtime; + + /** + * The object name under which the bean is registered. + */ + private final ObjectName objectName; + + HotSpotGraalRuntimeMBean(ObjectName objectName, HotSpotGraalRuntime runtime) { + this.objectName = objectName; + this.runtime = runtime; + } + + ObjectName getObjectName() { + return objectName; + } + + HotSpotGraalRuntime getRuntime() { + return runtime; + } + + private static final boolean DEBUG = Boolean.getBoolean(HotSpotGraalRuntimeMBean.class.getSimpleName() + ".debug"); + + @Override + public Object getAttribute(String name) throws AttributeNotFoundException { + String[] result = runtime.getOptionValues(name); + String value = result[0]; + if (value == null) { + throw new AttributeNotFoundException(name); + } + if (DEBUG) { + System.out.printf("getAttribute: %s = %s (type: %s)%n", name, value, value == null ? "null" : value.getClass().getName()); + } + return result[0]; + } + + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality on the receiver is what we want") + @Override + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException { + String name = attribute.getName(); + Object value = attribute.getValue(); + String svalue = String.valueOf(value); + if (DEBUG) { + System.out.printf("setAttribute: %s = %s (type: %s)%n", name, svalue, value == null ? "null" : value.getClass().getName()); + } + String[] result = runtime.setOptionValues(new String[]{name}, new String[]{svalue}); + if (result[0] != name) { + if (result[0] == null) { + throw new AttributeNotFoundException(name); + } + throw new InvalidAttributeValueException(result[0]); + } + } + + @Override + public AttributeList getAttributes(String[] names) { + String[] values = runtime.getOptionValues(names); + AttributeList list = new AttributeList(); + for (int i = 0; i < names.length; i++) { + String value = values[i]; + String name = names[i]; + if (value == null) { + TTY.printf("No such option named %s%n", name); + } else { + if (DEBUG) { + System.out.printf("getAttributes: %s = %s (type: %s)%n", name, value, value == null ? "null" : value.getClass().getName()); + } + list.add(new Attribute(name, value)); + } + } + return list; + } + + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality on the receiver is what we want") + @Override + public AttributeList setAttributes(AttributeList attributes) { + String[] names = new String[attributes.size()]; + String[] values = new String[attributes.size()]; + + int i = 0; + for (Attribute attr : attributes.asList()) { + String name = attr.getName(); + names[i] = name; + Object value = attr.getValue(); + String svalue = String.valueOf(value); + values[i] = svalue; + if (DEBUG) { + System.out.printf("setAttributes: %s = %s (type: %s)%n", name, svalue, value == null ? "null" : value.getClass().getName()); + } + i++; + } + String[] result = runtime.setOptionValues(names, values); + AttributeList setOk = new AttributeList(); + i = 0; + for (Attribute attr : attributes.asList()) { + if (names[i] == result[i]) { + setOk.add(attr); + } else if (result[i] == null) { + TTY.printf("Error setting %s to %s: unknown option%n", attr.getName(), attr.getValue()); + } else { + TTY.printf("Error setting %s to %s: %s%n", attr.getName(), attr.getValue(), result[i]); + } + i++; + } + return setOk; + } + + @Override + public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { + try { + if (DEBUG) { + System.out.printf("invoke: %s%s%n", actionName, Arrays.asList(params)); + } + Object retvalue = runtime.invokeManagementAction(actionName, params); + if (DEBUG) { + System.out.printf("invoke: %s%s = %s%n", actionName, Arrays.asList(params), retvalue); + } + return retvalue; + } catch (Exception ex) { + throw new ReflectionException(ex); + } + } + + @Override + public MBeanInfo getMBeanInfo() { + List attrs = new ArrayList<>(); + for (OptionDescriptor option : getOptionDescriptors().getValues()) { + Class optionValueType = option.getOptionValueType(); + if (Enum.class.isAssignableFrom(optionValueType)) { + // Enum values are passed through + // the management interface as Strings. + optionValueType = String.class; + } + attrs.add(new MBeanAttributeInfo(option.getName(), optionValueType.getName(), option.getHelp(), true, true, false)); + } + attrs.sort(new Comparator() { + @Override + public int compare(MBeanAttributeInfo o1, MBeanAttributeInfo o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + MBeanOperationInfo[] ops = { + new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{ + new MBeanParameterInfo("className", "java.lang.String", "Class to observe"), + new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"), + }, "void", MBeanOperationInfo.ACTION), + new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{ + new MBeanParameterInfo("className", "java.lang.String", "Class to observe"), + new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"), + new MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"), + }, "void", MBeanOperationInfo.ACTION), + new MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new MBeanParameterInfo[]{ + new MBeanParameterInfo("className", "java.lang.String", "Class to observe"), + new MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"), + new MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"), + new MBeanParameterInfo("host", "java.lang.String", "The host where the IGV tool is running at"), + new MBeanParameterInfo("port", "int", "The port where the IGV tool is listening at"), + }, "void", MBeanOperationInfo.ACTION) + }; + + return new MBeanInfo( + HotSpotGraalRuntimeMBean.class.getName(), + "Graal", + attrs.toArray(new MBeanAttributeInfo[attrs.size()]), + null, ops, null); + } + + private static EconomicMap getOptionDescriptors() { + EconomicMap result = EconomicMap.create(); + for (OptionDescriptors set : OptionsParser.getOptionsLoader()) { + for (OptionDescriptor option : set) { + result.put(option.getName(), option); + } + } + return result; + } +} diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/JMXServiceProvider.java b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/JMXServiceProvider.java new file mode 100644 index 00000000000..6e754b0ae25 --- /dev/null +++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/JMXServiceProvider.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.management; + +import static java.lang.Thread.currentThread; + +import java.lang.management.ManagementFactory; +import java.util.List; + +import org.graalvm.compiler.serviceprovider.ServiceProvider; +import org.graalvm.compiler.serviceprovider.GraalServices.JMXService; + +import com.sun.management.ThreadMXBean; + +/** + * Implementation of {@link JMXService} for JDK 11 and later. + */ +@ServiceProvider(JMXService.class) +public class JMXServiceProvider extends JMXService { + private final ThreadMXBean threadMXBean = (ThreadMXBean) ManagementFactory.getThreadMXBean(); + + @Override + protected long getThreadAllocatedBytes(long id) { + return threadMXBean.getThreadAllocatedBytes(id); + } + + @Override + protected long getCurrentThreadCpuTime() { + long[] times = threadMXBean.getThreadCpuTime(new long[]{currentThread().getId()}); + return times[0]; + } + + @Override + protected boolean isThreadAllocatedMemorySupported() { + return threadMXBean.isThreadAllocatedMemorySupported(); + } + + @Override + protected boolean isCurrentThreadCpuTimeSupported() { + return threadMXBean.isThreadCpuTimeSupported(); + } + + @Override + protected List getInputArguments() { + return ManagementFactory.getRuntimeMXBean().getInputArguments(); + } +} diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/package-info.java b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/package-info.java new file mode 100644 index 00000000000..d52c598c059 --- /dev/null +++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK 11 and later versioned overlay for the {@code jdk.internal.vm.compiler.management} module. + * This cannot be used in JDK 10 where {@code jdk.internal.vm.compiler.management} is a + * non-upgradeable module. + */ +package org.graalvm.compiler.hotspot.management; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapImplTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java similarity index 93% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapImplTest.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java index 68a12f572a1..0e10c9b9e30 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapImplTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java @@ -22,15 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections.test; +package jdk.internal.vm.compiler.collections.test; import java.util.Arrays; import java.util.Iterator; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicSet; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicSet; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapLargeTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java similarity index 96% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapLargeTest.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java index aa651d75515..8fc76b5d376 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapLargeTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections.test; +package jdk.internal.vm.compiler.collections.test; import java.util.Arrays; import java.util.Collection; @@ -31,10 +31,10 @@ import java.util.LinkedHashMap; import java.util.Objects; import java.util.Random; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java similarity index 93% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapTest.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java index b6449528a2b..1bf98ceaf22 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java @@ -22,12 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections.test; +package jdk.internal.vm.compiler.collections.test; import java.util.LinkedHashMap; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicSetTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java similarity index 96% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicSetTest.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java index 9434a8bc7b6..5420b32b2cf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicSetTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java @@ -22,14 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections.test; +package jdk.internal.vm.compiler.collections.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EquivalenceTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java similarity index 96% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EquivalenceTest.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java index 7af76d44b67..74a321bd380 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EquivalenceTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java @@ -22,9 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections.test; +package jdk.internal.vm.compiler.collections.test; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.Equivalence; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/PairTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java similarity index 95% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/PairTest.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java index 730d1d4a6cb..8337e1a0a43 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/PairTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java @@ -22,9 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections.test; +package jdk.internal.vm.compiler.collections.test; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java similarity index 99% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java index 4eae215ca44..a635f37bb3d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; import java.util.Iterator; import java.util.Map; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java similarity index 99% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java index 827fc09df31..e3e6c85a456 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; import java.util.Iterator; import java.util.Objects; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicSet.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java similarity index 99% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicSet.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java index 32b2af28dcc..949a8fb5a30 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; import java.util.Iterator; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Equivalence.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java similarity index 98% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Equivalence.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java index ddade583082..ccc369654b6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Equivalence.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; /** * Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT}, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/MapCursor.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java similarity index 97% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/MapCursor.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java index 974a56ac3dc..3f30e9fdfce 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/MapCursor.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; /** * Cursor to iterate over a mutable map. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Pair.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java similarity index 98% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Pair.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java index 6cba3764391..d2aff0c879f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Pair.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; import java.util.Objects; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java similarity index 98% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java index f246f9626f9..9bd35f9d702 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; /** * Unmodifiable memory efficient map data structure. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicSet.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java similarity index 98% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicSet.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java index aa9aa76e42a..b4ccfe2c0b5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; /** * Unmodifiable memory efficient set data structure. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableMapCursor.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java similarity index 97% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableMapCursor.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java index 49d3e4bd475..74038f88a27 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableMapCursor.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; /** * Cursor to iterate over a map without changing its contents. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/package-info.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java similarity index 86% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/package-info.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java index fcf78805175..ee0e358b88a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/package-info.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java @@ -22,12 +22,17 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +/* + @ApiInfo( + group="Graal SDK" + ) + */ /** * The Graal-SDK collections package contains memory efficient data structures. * - * @see org.graalvm.collections.EconomicMap - * @see org.graalvm.collections.EconomicSet + * @see jdk.internal.vm.compiler.collections.EconomicMap + * @see jdk.internal.vm.compiler.collections.EconomicSet * * @since 1.0 */ -package org.graalvm.collections; +package jdk.internal.vm.compiler.collections; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/ComparableWord.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java similarity index 90% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/ComparableWord.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java index eb5af36e729..72006e4cbf8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/ComparableWord.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java @@ -22,8 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; +/** + * A machine-word-sized value that can be compared for equality. + * + * @since 1.0 + */ public interface ComparableWord extends WordBase { /** @@ -31,6 +36,8 @@ public interface ComparableWord extends WordBase { * * @param val value to which this word is to be compared. * @return {@code this == val} + * + * @since 1.0 */ boolean equal(ComparableWord val); @@ -39,6 +46,8 @@ public interface ComparableWord extends WordBase { * * @param val value to which this word is to be compared. * @return {@code this != val} + * + * @since 1.0 */ boolean notEqual(ComparableWord val); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/LocationIdentity.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java similarity index 70% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/LocationIdentity.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java index eb88f5f9289..171216b5495 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/LocationIdentity.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java @@ -22,17 +22,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; // JaCoCo Exclude /** * Marker interface for location identities. A different location identity of two memory accesses * guarantees that the two accesses do not interfere. - * + *

* Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use * {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys. + * + * @since 1.0 */ public abstract class LocationIdentity { @@ -60,13 +62,39 @@ public abstract class LocationIdentity { } } + /** + * Creates a new location identity. Subclasses are responsible to provide proper implementations + * of {@link #equals} and {@link #hashCode}. + * + * @since 1.0 + */ + protected LocationIdentity() { + } + + /** + * Indicates that the given location is the union of all possible mutable locations. A write to + * such a location kill all reads from mutable locations and a read from this location is killed + * by any write (except for initialization writes). + * + * @since 1.0 + */ public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity(); + + /** + * Location only allowed to be used for writes. Indicates that a completely new memory location + * is written. Kills no read. The previous value at the given location must be either + * uninitialized or null. Writes to this location do not need a GC pre-barrier. + * + * @since 1.0 + */ public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity(); /** * Indicates that the given location is the union of all possible mutable locations. A write to * such a location kill all reads from mutable locations and a read from this location is killed * by any write (except for initialization writes). + * + * @since 1.0 */ public static LocationIdentity any() { return ANY_LOCATION; @@ -76,6 +104,8 @@ public abstract class LocationIdentity { * Location only allowed to be used for writes. Indicates that a completely new memory location * is written. Kills no read. The previous value at the given location must be either * uninitialized or null. Writes to this location do not need a GC pre-barrier. + * + * @since 1.0 */ public static LocationIdentity init() { return INIT_LOCATION; @@ -84,25 +114,53 @@ public abstract class LocationIdentity { /** * Denotes a location is unchanging in all cases. Not that this is different than the Java * notion of final which only requires definite assignment. + * + * @since 1.0 */ public abstract boolean isImmutable(); + /** + * The inversion of {@link #isImmutable}. + * + * @since 1.0 + */ public final boolean isMutable() { return !isImmutable(); } + /** + * Returns true if this location identity is {@link #any}. + * + * @since 1.0 + */ public final boolean isAny() { return this == ANY_LOCATION; } + /** + * Returns true if this location identity is {@link #init}. + * + * @since 1.0 + */ public final boolean isInit() { return this == INIT_LOCATION; } + /** + * Returns true if this location identity is not {@link #any}. + * + * @since 1.0 + */ public final boolean isSingle() { return this != ANY_LOCATION; } + /** + * Returns true if the memory slice denoted by this location identity may overlap with the + * provided other location identity. + * + * @since 1.0 + */ public final boolean overlaps(LocationIdentity other) { return isAny() || other.isAny() || this.equals(other); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/Pointer.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java similarity index 73% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/Pointer.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java index 395693fa675..4968631e743 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/Pointer.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; /** * Lowest-level memory access of native C memory. @@ -30,6 +30,8 @@ package org.graalvm.word; * Do not use these methods to access Java objects. These methods access the raw memory without any * null checks, read- or write barriers. Even when the VM uses compressed pointers, then readObject * and writeObject methods access uncompressed pointers. + * + * @since 1.0 */ public interface Pointer extends UnsignedWord, PointerBase { @@ -39,6 +41,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * that can i.e., processed by the garbage collector. * * @return this Pointer cast to Object. + * + * @since 1.0 */ Object toObject(); @@ -48,6 +52,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * that can i.e., processed by the garbage collector and the Pointer does not contain 0. * * @return this Pointer cast to non-null Object. + * + * @since 1.0 */ Object toObjectNonNull(); @@ -62,6 +68,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ byte readByte(WordBase offset, LocationIdentity locationIdentity); @@ -76,6 +84,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ char readChar(WordBase offset, LocationIdentity locationIdentity); @@ -90,6 +100,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ short readShort(WordBase offset, LocationIdentity locationIdentity); @@ -104,6 +116,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ int readInt(WordBase offset, LocationIdentity locationIdentity); @@ -118,6 +132,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ long readLong(WordBase offset, LocationIdentity locationIdentity); @@ -132,6 +148,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ float readFloat(WordBase offset, LocationIdentity locationIdentity); @@ -146,6 +164,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ double readDouble(WordBase offset, LocationIdentity locationIdentity); @@ -160,6 +180,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ T readWord(WordBase offset, LocationIdentity locationIdentity); @@ -174,6 +196,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ Object readObject(WordBase offset, LocationIdentity locationIdentity); @@ -184,6 +208,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ byte readByte(int offset, LocationIdentity locationIdentity); @@ -194,6 +220,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ char readChar(int offset, LocationIdentity locationIdentity); @@ -204,6 +232,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ short readShort(int offset, LocationIdentity locationIdentity); @@ -214,6 +244,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ int readInt(int offset, LocationIdentity locationIdentity); @@ -224,6 +256,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ long readLong(int offset, LocationIdentity locationIdentity); @@ -234,6 +268,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ float readFloat(int offset, LocationIdentity locationIdentity); @@ -244,6 +280,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ double readDouble(int offset, LocationIdentity locationIdentity); @@ -254,6 +292,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ T readWord(int offset, LocationIdentity locationIdentity); @@ -264,6 +304,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the read * @return the result of the memory access + * + * @since 1.0 */ Object readObject(int offset, LocationIdentity locationIdentity); @@ -278,6 +320,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity); @@ -292,6 +336,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeChar(WordBase offset, char val, LocationIdentity locationIdentity); @@ -306,6 +352,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeShort(WordBase offset, short val, LocationIdentity locationIdentity); @@ -320,6 +368,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeInt(WordBase offset, int val, LocationIdentity locationIdentity); @@ -334,6 +384,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeLong(WordBase offset, long val, LocationIdentity locationIdentity); @@ -348,6 +400,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity); @@ -362,6 +416,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity); @@ -376,6 +432,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); @@ -390,6 +448,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity); @@ -404,6 +464,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity); @@ -414,6 +476,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeByte(int offset, byte val, LocationIdentity locationIdentity); @@ -424,6 +488,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeChar(int offset, char val, LocationIdentity locationIdentity); @@ -434,6 +500,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeShort(int offset, short val, LocationIdentity locationIdentity); @@ -444,6 +512,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeInt(int offset, int val, LocationIdentity locationIdentity); @@ -454,6 +524,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeLong(int offset, long val, LocationIdentity locationIdentity); @@ -464,6 +536,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeFloat(int offset, float val, LocationIdentity locationIdentity); @@ -474,6 +548,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeDouble(int offset, double val, LocationIdentity locationIdentity); @@ -484,6 +560,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeWord(int offset, WordBase val, LocationIdentity locationIdentity); @@ -494,6 +572,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void initializeLong(int offset, long val, LocationIdentity locationIdentity); @@ -504,6 +584,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * @param offset the signed offset for the memory access * @param locationIdentity the identity of the write * @param val the value to be written to memory + * + * @since 1.0 */ void writeObject(int offset, Object val, LocationIdentity locationIdentity); @@ -517,6 +599,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ byte readByte(WordBase offset); @@ -530,6 +614,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ char readChar(WordBase offset); @@ -543,6 +629,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ short readShort(WordBase offset); @@ -556,6 +644,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ int readInt(WordBase offset); @@ -569,6 +659,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ long readLong(WordBase offset); @@ -582,6 +674,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ float readFloat(WordBase offset); @@ -595,6 +689,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ double readDouble(WordBase offset); @@ -608,6 +704,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ T readWord(WordBase offset); @@ -621,6 +719,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ Object readObject(WordBase offset); @@ -630,6 +730,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ byte readByte(int offset); @@ -639,6 +741,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ char readChar(int offset); @@ -648,6 +752,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ short readShort(int offset); @@ -657,6 +763,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ int readInt(int offset); @@ -666,6 +774,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ long readLong(int offset); @@ -675,6 +785,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ float readFloat(int offset); @@ -684,6 +796,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ double readDouble(int offset); @@ -693,6 +807,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ T readWord(int offset); @@ -702,6 +818,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @return the result of the memory access + * + * @since 1.0 */ Object readObject(int offset); @@ -715,6 +833,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeByte(WordBase offset, byte val); @@ -728,6 +848,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeChar(WordBase offset, char val); @@ -741,6 +863,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeShort(WordBase offset, short val); @@ -754,6 +878,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeInt(WordBase offset, int val); @@ -767,6 +893,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeLong(WordBase offset, long val); @@ -780,6 +908,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeFloat(WordBase offset, float val); @@ -793,6 +923,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeDouble(WordBase offset, double val); @@ -806,6 +938,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeWord(WordBase offset, WordBase val); @@ -819,23 +953,157 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeObject(WordBase offset, Object val); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ int compareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ long compareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ T compareAndSwapWord(WordBase offset, T expectedValue, T newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ Object compareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + *

+ * The offset is always treated as a {@link SignedWord} value. However, the static type is + * {@link WordBase} to avoid the frequent casts of {@link UnsignedWord} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity); /** @@ -844,6 +1112,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeByte(int offset, byte val); @@ -853,6 +1123,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeChar(int offset, char val); @@ -862,6 +1134,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeShort(int offset, short val); @@ -871,6 +1145,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeInt(int offset, int val); @@ -880,6 +1156,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeLong(int offset, long val); @@ -889,6 +1167,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeFloat(int offset, float val); @@ -898,6 +1178,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeDouble(int offset, double val); @@ -907,6 +1189,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeWord(int offset, WordBase val); @@ -916,50 +1200,216 @@ public interface Pointer extends UnsignedWord, PointerBase { * * @param offset the signed offset for the memory access * @param val the value to be written to memory + * + * @since 1.0 */ void writeObject(int offset, Object val); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ int compareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ long compareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ T compareAndSwapWord(int offset, T expectedValue, T newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return The value after the atomic exchange + * + * @since 1.0 + */ Object compareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity); + /** + * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * offset are in bytes. + * + * @param offset the signed offset for the memory access + * @param expectedValue the expected value of the atomic exchange + * @param newValue the new value of the atomic exchange + * @param locationIdentity the identity of the memory location + * @return {@code true} if successful. False return indicates that the actual value was not + * equal to the expected value. + * + * @since 1.0 + */ boolean logicCompareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity); // Math functions that are defined in Unsigned, but known to preserve the // pointer-characteristics. // It is therefore safe that they return a static type of Pointer instead of Unsigned. + /** + * Returns a Pointer whose value is {@code (this + val)}. + * + * @param val value to be added to this Pointer. + * @return {@code this + val} + * + * @since 1.0 + */ @Override Pointer add(UnsignedWord val); + /** + * Returns a Pointer whose value is {@code (this + val)}. + * + * @param val value to be added to this Pointer. + * @return {@code this + val} + * + * @since 1.0 + */ @Override Pointer add(int val); + /** + * Returns a Pointer whose value is {@code (this - val)}. + * + * @param val value to be subtracted from this Pointer. + * @return {@code this - val} + * + * @since 1.0 + */ @Override Pointer subtract(UnsignedWord val); + /** + * Returns a Pointer whose value is {@code (this - val)}. + * + * @param val value to be subtracted from this Pointer. + * @return {@code this - val} + * + * @since 1.0 + */ @Override Pointer subtract(int val); + /** + * Returns a Pointer whose value is {@code (this & val)}. + * + * @param val value to be AND'ed with this Pointer. + * @return {@code this & val} + * + * @since 1.0 + */ @Override Pointer and(UnsignedWord val); + /** + * Returns a Pointer whose value is {@code (this & val)}. + * + * @param val value to be AND'ed with this Pointer. + * @return {@code this & val} + * + * @since 1.0 + */ @Override Pointer and(int val); + /** + * Returns a Pointer whose value is {@code (this | val)}. + * + * @param val value to be OR'ed with this Pointer. + * @return {@code this | val} + * + * @since 1.0 + */ @Override Pointer or(UnsignedWord val); + /** + * Returns a Pointer whose value is {@code (this | val)}. + * + * @param val value to be OR'ed with this Pointer. + * @return {@code this | val} + * + * @since 1.0 + */ @Override Pointer or(int val); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/PointerBase.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java similarity index 94% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/PointerBase.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java index 2d178d8f8e5..d9c7ea34666 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/PointerBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java @@ -22,21 +22,27 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; /** * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not * necessarily all the memory access methods defined in {@link Pointer}). + * + * @since 1.0 */ public interface PointerBase extends ComparableWord { /** * Returns true if this pointer is the {@link WordFactory#nullPointer null pointer}. + * + * @since 1.0 */ boolean isNull(); /** * Returns true if this pointer is not the {@link WordFactory#nullPointer null pointer}. + * + * @since 1.0 */ boolean isNonNull(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/SignedWord.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java similarity index 90% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/SignedWord.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java index 8299395f35b..84ef1494ff3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/SignedWord.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java @@ -22,8 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; +/** + * Represents a signed word-sized value. + * + * @since 1.0 + */ public interface SignedWord extends ComparableWord { /** @@ -31,6 +36,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be added to this Signed. * @return {@code this + val} + * + * @since 1.0 */ SignedWord add(SignedWord val); @@ -39,6 +46,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be subtracted from this Signed. * @return {@code this - val} + * + * @since 1.0 */ SignedWord subtract(SignedWord val); @@ -47,6 +56,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be multiplied by this Signed. * @return {@code this * val} + * + * @since 1.0 */ SignedWord multiply(SignedWord val); @@ -55,6 +66,8 @@ public interface SignedWord extends ComparableWord { * * @param val value by which this Signed is to be divided. * @return {@code this / val} + * + * @since 1.0 */ SignedWord signedDivide(SignedWord val); @@ -63,6 +76,8 @@ public interface SignedWord extends ComparableWord { * * @param val value by which this Signed is to be divided, and the remainder computed. * @return {@code this % val} + * + * @since 1.0 */ SignedWord signedRemainder(SignedWord val); @@ -71,6 +86,8 @@ public interface SignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this << n} + * + * @since 1.0 */ SignedWord shiftLeft(UnsignedWord n); @@ -79,6 +96,8 @@ public interface SignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this >> n} + * + * @since 1.0 */ SignedWord signedShiftRight(UnsignedWord n); @@ -88,6 +107,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be AND'ed with this Signed. * @return {@code this & val} + * + * @since 1.0 */ SignedWord and(SignedWord val); @@ -97,6 +118,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be OR'ed with this Signed. * @return {@code this | val} + * + * @since 1.0 */ SignedWord or(SignedWord val); @@ -106,6 +129,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be XOR'ed with this Signed. * @return {@code this ^ val} + * + * @since 1.0 */ SignedWord xor(SignedWord val); @@ -114,6 +139,8 @@ public interface SignedWord extends ComparableWord { * only if this Signed is non-negative.) * * @return {@code ~this} + * + * @since 1.0 */ SignedWord not(); @@ -122,6 +149,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this == val} + * + * @since 1.0 */ boolean equal(SignedWord val); @@ -130,6 +159,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this != val} + * + * @since 1.0 */ boolean notEqual(SignedWord val); @@ -138,6 +169,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this < val} + * + * @since 1.0 */ boolean lessThan(SignedWord val); @@ -146,6 +179,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this <= val} + * + * @since 1.0 */ boolean lessOrEqual(SignedWord val); @@ -154,6 +189,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this > val} + * + * @since 1.0 */ boolean greaterThan(SignedWord val); @@ -162,6 +199,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this >= val} + * + * @since 1.0 */ boolean greaterOrEqual(SignedWord val); @@ -170,6 +209,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be added to this Signed. * @return {@code this + val} + * + * @since 1.0 */ SignedWord add(int val); @@ -178,6 +219,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be subtracted from this Signed. * @return {@code this - val} + * + * @since 1.0 */ SignedWord subtract(int val); @@ -186,6 +229,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be multiplied by this Signed. * @return {@code this * val} + * + * @since 1.0 */ SignedWord multiply(int val); @@ -194,6 +239,8 @@ public interface SignedWord extends ComparableWord { * * @param val value by which this Signed is to be divided. * @return {@code this / val} + * + * @since 1.0 */ SignedWord signedDivide(int val); @@ -202,6 +249,8 @@ public interface SignedWord extends ComparableWord { * * @param val value by which this Signed is to be divided, and the remainder computed. * @return {@code this % val} + * + * @since 1.0 */ SignedWord signedRemainder(int val); @@ -210,6 +259,8 @@ public interface SignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this << n} + * + * @since 1.0 */ SignedWord shiftLeft(int n); @@ -218,6 +269,8 @@ public interface SignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this >> n} + * + * @since 1.0 */ SignedWord signedShiftRight(int n); @@ -227,6 +280,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be AND'ed with this Signed. * @return {@code this & val} + * + * @since 1.0 */ SignedWord and(int val); @@ -236,6 +291,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be OR'ed with this Signed. * @return {@code this | val} + * + * @since 1.0 */ SignedWord or(int val); @@ -245,6 +302,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to be XOR'ed with this Signed. * @return {@code this ^ val} + * + * @since 1.0 */ SignedWord xor(int val); @@ -253,6 +312,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this == val} + * + * @since 1.0 */ boolean equal(int val); @@ -261,6 +322,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this != val} + * + * @since 1.0 */ boolean notEqual(int val); @@ -269,6 +332,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this < val} + * + * @since 1.0 */ boolean lessThan(int val); @@ -277,6 +342,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this <= val} + * + * @since 1.0 */ boolean lessOrEqual(int val); @@ -285,6 +352,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this > val} + * + * @since 1.0 */ boolean greaterThan(int val); @@ -293,6 +362,8 @@ public interface SignedWord extends ComparableWord { * * @param val value to which this Signed is to be compared. * @return {@code this >= val} + * + * @since 1.0 */ boolean greaterOrEqual(int val); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/UnsignedWord.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java similarity index 92% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/UnsignedWord.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java index 0c72c631737..480966cb7a3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/UnsignedWord.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java @@ -22,8 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; +/** + * Represents an unsigned word-sized value. + * + * @since 1.0 + */ public interface UnsignedWord extends ComparableWord { /** @@ -31,6 +36,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be added to this Unsigned. * @return {@code this + val} + * + * @since 1.0 */ UnsignedWord add(UnsignedWord val); @@ -39,6 +46,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be subtracted from this Unsigned. * @return {@code this - val} + * + * @since 1.0 */ UnsignedWord subtract(UnsignedWord val); @@ -47,6 +56,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be multiplied by this Unsigned. * @return {@code this * val} + * + * @since 1.0 */ UnsignedWord multiply(UnsignedWord val); @@ -55,6 +66,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value by which this Unsigned is to be divided. * @return {@code this / val} + * + * @since 1.0 */ UnsignedWord unsignedDivide(UnsignedWord val); @@ -63,6 +76,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value by which this Unsigned is to be divided, and the remainder computed. * @return {@code this % val} + * + * @since 1.0 */ UnsignedWord unsignedRemainder(UnsignedWord val); @@ -71,6 +86,8 @@ public interface UnsignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this << n} + * + * @since 1.0 */ UnsignedWord shiftLeft(UnsignedWord n); @@ -79,6 +96,8 @@ public interface UnsignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this >> n} + * + * @since 1.0 */ UnsignedWord unsignedShiftRight(UnsignedWord n); @@ -87,6 +106,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be AND'ed with this Unsigned. * @return {@code this & val} + * + * @since 1.0 */ UnsignedWord and(UnsignedWord val); @@ -95,6 +116,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be OR'ed with this Unsigned. * @return {@code this | val} + * + * @since 1.0 */ UnsignedWord or(UnsignedWord val); @@ -103,6 +126,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be XOR'ed with this Unsigned. * @return {@code this ^ val} + * + * @since 1.0 */ UnsignedWord xor(UnsignedWord val); @@ -110,6 +135,8 @@ public interface UnsignedWord extends ComparableWord { * Returns a Unsigned whose value is {@code (~this)}. * * @return {@code ~this} + * + * @since 1.0 */ UnsignedWord not(); @@ -118,6 +145,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this == val} + * + * @since 1.0 */ boolean equal(UnsignedWord val); @@ -126,6 +155,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this != val} + * + * @since 1.0 */ boolean notEqual(UnsignedWord val); @@ -134,6 +165,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this < val} + * + * @since 1.0 */ boolean belowThan(UnsignedWord val); @@ -142,6 +175,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this <= val} + * + * @since 1.0 */ boolean belowOrEqual(UnsignedWord val); @@ -150,6 +185,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this > val} + * + * @since 1.0 */ boolean aboveThan(UnsignedWord val); @@ -158,6 +195,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this >= val} + * + * @since 1.0 */ boolean aboveOrEqual(UnsignedWord val); @@ -169,6 +208,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be added to this Unsigned. * @return {@code this + val} + * + * @since 1.0 */ UnsignedWord add(int val); @@ -180,6 +221,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be subtracted from this Unsigned. * @return {@code this - val} + * + * @since 1.0 */ UnsignedWord subtract(int val); @@ -191,6 +234,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be multiplied by this Unsigned. * @return {@code this * val} + * + * @since 1.0 */ UnsignedWord multiply(int val); @@ -202,6 +247,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value by which this Unsigned is to be divided. * @return {@code this / val} + * + * @since 1.0 */ UnsignedWord unsignedDivide(int val); @@ -213,6 +260,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value by which this Unsigned is to be divided, and the remainder computed. * @return {@code this % val} + * + * @since 1.0 */ UnsignedWord unsignedRemainder(int val); @@ -224,6 +273,8 @@ public interface UnsignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this << n} + * + * @since 1.0 */ UnsignedWord shiftLeft(int n); @@ -235,6 +286,8 @@ public interface UnsignedWord extends ComparableWord { * * @param n shift distance, in bits. * @return {@code this >> n} + * + * @since 1.0 */ UnsignedWord unsignedShiftRight(int n); @@ -246,6 +299,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be AND'ed with this Unsigned. * @return {@code this & val} + * + * @since 1.0 */ UnsignedWord and(int val); @@ -257,6 +312,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be OR'ed with this Unsigned. * @return {@code this | val} + * + * @since 1.0 */ UnsignedWord or(int val); @@ -268,6 +325,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to be XOR'ed with this Unsigned. * @return {@code this ^ val} + * + * @since 1.0 */ UnsignedWord xor(int val); @@ -279,6 +338,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this == val} + * + * @since 1.0 */ boolean equal(int val); @@ -290,6 +351,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this != val} + * + * @since 1.0 */ boolean notEqual(int val); @@ -301,6 +364,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this < val} + * + * @since 1.0 */ boolean belowThan(int val); @@ -312,6 +377,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this <= val} + * + * @since 1.0 */ boolean belowOrEqual(int val); @@ -323,6 +390,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this > val} + * + * @since 1.0 */ boolean aboveThan(int val); @@ -334,6 +403,8 @@ public interface UnsignedWord extends ComparableWord { * * @param val value to which this Unsigned is to be compared. * @return {@code this >= val} + * + * @since 1.0 */ boolean aboveOrEqual(int val); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/WordBase.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java similarity index 86% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/WordBase.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java index 9e814c82b96..3f1fc87fe9a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/WordBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java @@ -22,16 +22,28 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; +/** + * The root of the interface hierarchy for machine-word-sized values. + * + * @since 1.0 + */ public interface WordBase { + /** + * Conversion to a Java primitive value. + * + * @since 1.0 + */ long rawValue(); /** * This is deprecated because of the easy to mistype name collision between {@link #equals} and * the other word based equality routines. In general you should never be statically calling * this method anyway. + * + * @since 1.0 */ @Override @Deprecated diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/WordFactory.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java similarity index 67% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/WordFactory.java rename to src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java index 4fd279aabff..28984c05cb2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/src/org/graalvm/word/WordFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java @@ -22,44 +22,20 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.word; +package jdk.internal.vm.compiler.word; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import jdk.internal.vm.compiler.word.impl.WordBoxFactory; +import jdk.internal.vm.compiler.word.impl.WordFactoryOpcode; +import jdk.internal.vm.compiler.word.impl.WordFactoryOperation; -public abstract class WordFactory { +/** + * Provides factory method to create machine-word-sized values. + * + * @since 1.0 + */ +public final class WordFactory { - /** - * Links a method to a canonical operation represented by an {@link FactoryOpcode} val. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - protected @interface FactoryOperation { - FactoryOpcode opcode(); - } - - /** - * The canonical {@link FactoryOperation} represented by a method in a word type. - */ - protected enum FactoryOpcode { - ZERO, - FROM_UNSIGNED, - FROM_SIGNED, - } - - protected interface BoxFactory { - T box(long val); - } - - protected static BoxFactory boxFactory; - - /** - * We allow subclassing, because only subclasses can access the protected inner classes that we - * use to mark the operations. - */ - protected WordFactory() { + private WordFactory() { } /** @@ -67,10 +43,12 @@ public abstract class WordFactory { * unsigned zero. * * @return the constant 0. + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.ZERO) + @WordFactoryOperation(opcode = WordFactoryOpcode.ZERO) public static T zero() { - return boxFactory.box(0L); + return WordBoxFactory.box(0L); } /** @@ -78,10 +56,12 @@ public abstract class WordFactory { * unsigned {@link #zero}. * * @return the null pointer. + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.ZERO) + @WordFactoryOperation(opcode = WordFactoryOpcode.ZERO) public static T nullPointer() { - return boxFactory.box(0L); + return WordBoxFactory.box(0L); } /** @@ -90,10 +70,12 @@ public abstract class WordFactory { * * @param val a 64 bit unsigned value * @return the value cast to Word + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.FROM_UNSIGNED) + @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED) public static T unsigned(long val) { - return boxFactory.box(val); + return WordBoxFactory.box(val); } /** @@ -102,10 +84,12 @@ public abstract class WordFactory { * * @param val a 64 bit unsigned value * @return the value cast to PointerBase + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.FROM_UNSIGNED) + @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED) public static T pointer(long val) { - return boxFactory.box(val); + return WordBoxFactory.box(val); } /** @@ -114,10 +98,12 @@ public abstract class WordFactory { * * @param val a 32 bit unsigned value * @return the value cast to Word + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.FROM_UNSIGNED) + @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_UNSIGNED) public static T unsigned(int val) { - return boxFactory.box(val & 0xffffffffL); + return WordBoxFactory.box(val & 0xffffffffL); } /** @@ -126,10 +112,12 @@ public abstract class WordFactory { * * @param val a 64 bit signed value * @return the value cast to Word + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.FROM_SIGNED) + @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_SIGNED) public static T signed(long val) { - return boxFactory.box(val); + return WordBoxFactory.box(val); } /** @@ -138,9 +126,11 @@ public abstract class WordFactory { * * @param val a 32 bit signed value * @return the value cast to Word + * + * @since 1.0 */ - @FactoryOperation(opcode = FactoryOpcode.FROM_SIGNED) + @WordFactoryOperation(opcode = WordFactoryOpcode.FROM_SIGNED) public static T signed(int val) { - return boxFactory.box(val); + return WordBoxFactory.box(val); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java new file mode 100644 index 00000000000..66df8baffa0 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.vm.compiler.word.impl; + +import jdk.internal.vm.compiler.word.WordBase; + +/** + * Base class for a factory to create boxed {@link Word} instances. A concrete subclass must + * initialize {@link #boxFactory}. + */ +public abstract class WordBoxFactory { + + protected static WordBoxFactory boxFactory; + + protected abstract T boxImpl(long val); + + public static T box(long val) { + return boxFactory.boxImpl(val); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java new file mode 100644 index 00000000000..15f52fee522 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.vm.compiler.word.impl; + +/** + * The canonical {@link WordFactoryOperation} represented by a method in a word type. + */ +public enum WordFactoryOpcode { + ZERO, + FROM_UNSIGNED, + FROM_SIGNED, +} diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java new file mode 100644 index 00000000000..e713efe43c4 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.vm.compiler.word.impl; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Links a method to a canonical operation represented by an {@link WordFactoryOpcode} val. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface WordFactoryOperation { + WordFactoryOpcode opcode(); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java new file mode 100644 index 00000000000..833d59dd637 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + @ApiInfo( + group="Graal SDK" + ) + */ +/** + * This package provides a low-level mechanism to use machine-word-sized values in Java. The package + * can only be used in the context of native images or Graal snippets. + * + * @since 1.0 + */ +package jdk.internal.vm.compiler.word; \ No newline at end of file diff --git a/src/jdk.internal.vm.compiler/share/classes/module-info.java b/src/jdk.internal.vm.compiler/share/classes/module-info.java index 44c1259646d..199b09ba168 100644 --- a/src/jdk.internal.vm.compiler/share/classes/module-info.java +++ b/src/jdk.internal.vm.compiler/share/classes/module-info.java @@ -36,9 +36,10 @@ module jdk.internal.vm.compiler { uses org.graalvm.compiler.hotspot.CompilerConfigurationFactory; uses org.graalvm.compiler.hotspot.HotSpotBackendFactory; uses org.graalvm.compiler.hotspot.HotSpotCodeCacheListener; - uses org.graalvm.compiler.options.OptionValuesAccess; + uses org.graalvm.compiler.hotspot.HotSpotGraalManagementRegistration; uses org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; + exports jdk.internal.vm.compiler.collections to jdk.internal.vm.compiler.management; exports org.graalvm.compiler.api.directives to jdk.aot; exports org.graalvm.compiler.api.runtime to jdk.aot; exports org.graalvm.compiler.api.replacements to jdk.aot; @@ -46,9 +47,13 @@ module jdk.internal.vm.compiler { exports org.graalvm.compiler.bytecode to jdk.aot; exports org.graalvm.compiler.code to jdk.aot; exports org.graalvm.compiler.core to jdk.aot; - exports org.graalvm.compiler.core.common to jdk.aot; + exports org.graalvm.compiler.core.common to + jdk.aot, + jdk.internal.vm.compiler.management; exports org.graalvm.compiler.core.target to jdk.aot; - exports org.graalvm.compiler.debug to jdk.aot; + exports org.graalvm.compiler.debug to + jdk.aot, + jdk.internal.vm.compiler.management; exports org.graalvm.compiler.graph to jdk.aot; exports org.graalvm.compiler.hotspot to jdk.aot, @@ -62,12 +67,17 @@ module jdk.internal.vm.compiler { exports org.graalvm.compiler.lir.phases to jdk.aot; exports org.graalvm.compiler.nodes to jdk.aot; exports org.graalvm.compiler.nodes.graphbuilderconf to jdk.aot; - exports org.graalvm.compiler.options to jdk.aot; + exports org.graalvm.compiler.options to + jdk.aot, + jdk.internal.vm.compiler.management; exports org.graalvm.compiler.phases to jdk.aot; exports org.graalvm.compiler.phases.tiers to jdk.aot; exports org.graalvm.compiler.printer to jdk.aot; exports org.graalvm.compiler.runtime to jdk.aot; exports org.graalvm.compiler.replacements to jdk.aot; + exports org.graalvm.compiler.serviceprovider to + jdk.aot, + jdk.internal.vm.compiler.management; exports org.graalvm.compiler.word to jdk.aot; - exports org.graalvm.word to jdk.aot; + exports jdk.internal.vm.compiler.word to jdk.aot; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java index 9c579967920..1bb3fab634f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java @@ -206,12 +206,12 @@ class TestProtectedAssembler extends AArch64Assembler { } @Override - protected void bfm(int size, Register dst, Register src, int r, int s) { + public void bfm(int size, Register dst, Register src, int r, int s) { super.bfm(size, dst, src, r, s); } @Override - protected void ubfm(int size, Register dst, Register src, int r, int s) { + public void ubfm(int size, Register dst, Register src, int r, int s) { super.ubfm(size, dst, src, r, s); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java index 9298faf25a1..99d6c4833b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java @@ -35,6 +35,7 @@ import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BICS import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BLR; import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BR; import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BRK; +import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CAS; import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLREX; import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLS; import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLZ; @@ -118,6 +119,9 @@ import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; import org.graalvm.compiler.debug.GraalError; +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.aarch64.AArch64.CPUFeature; +import jdk.vm.ci.aarch64.AArch64.Flag; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.TargetDescription; @@ -471,6 +475,9 @@ public abstract class AArch64Assembler extends Assembler { private static final int BarrierOp = 0xD503301F; private static final int BarrierKindOffset = 8; + private static final int CASAcquireOffset = 22; + private static final int CASReleaseOffset = 15; + /** * Encoding for all instructions. */ @@ -501,6 +508,8 @@ public abstract class AArch64Assembler extends Assembler { LDP(0b1 << 22), STP(0b0 << 22), + CAS(0x08A07C00), + ADR(0x00000000), ADRP(0x80000000), @@ -740,6 +749,14 @@ public abstract class AArch64Assembler extends Assembler { super(target); } + public boolean supports(CPUFeature feature) { + return ((AArch64) target.arch).getFeatures().contains(feature); + } + + public boolean isFlagSet(Flag flag) { + return ((AArch64) target.arch).getFlags().contains(flag); + } + /* Conditional Branch (5.2.1) */ /** @@ -1311,6 +1328,20 @@ public abstract class AArch64Assembler extends Assembler { emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt)); } + /* Compare And Swap */ + public void cas(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) { + assert size == 32 || size == 64; + int transferSize = NumUtil.log2Ceil(size / 8); + compareAndSwapInstruction(CAS, rs, rt, rn, transferSize, acquire, release); + } + + private void compareAndSwapInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize, boolean acquire, boolean release) { + assert log2TransferSize >= 0 && log2TransferSize < 4; + assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt); + int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset; + emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << CASAcquireOffset | (release ? 1 : 0) << CASReleaseOffset); + } + /* PC-relative Address Calculation (5.4.4) */ /** @@ -1576,7 +1607,7 @@ public abstract class AArch64Assembler extends Assembler { * @param r must be in the range 0 to size - 1 * @param s must be in the range 0 to size - 1 */ - protected void bfm(int size, Register dst, Register src, int r, int s) { + public void bfm(int size, Register dst, Register src, int r, int s) { bitfieldInstruction(BFM, dst, src, r, s, generalFromSize(size)); } @@ -1589,7 +1620,7 @@ public abstract class AArch64Assembler extends Assembler { * @param r must be in the range 0 to size - 1 * @param s must be in the range 0 to size - 1 */ - protected void ubfm(int size, Register dst, Register src, int r, int s) { + public void ubfm(int size, Register dst, Register src, int r, int s) { bitfieldInstruction(UBFM, dst, src, r, s, generalFromSize(size)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java index 8e56035c3f1..7d395fb5e0a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java @@ -33,7 +33,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.graph.NodeSourcePosition; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java index 96570b3cb09..942bc5f3144 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/SourceStackTraceBailoutException.java @@ -32,8 +32,8 @@ import org.graalvm.compiler.core.common.PermanentBailoutException; public abstract class SourceStackTraceBailoutException extends PermanentBailoutException { private static final long serialVersionUID = 2144811793442316776L; - public static SourceStackTraceBailoutException create(Throwable cause, String format, StackTraceElement[] elements) { - return new SourceStackTraceBailoutException(cause, format) { + public static SourceStackTraceBailoutException create(Throwable cause, String reason, StackTraceElement[] elements) { + return new SourceStackTraceBailoutException(cause, reason) { private static final long serialVersionUID = 6279381376051787907L; @@ -46,7 +46,7 @@ public abstract class SourceStackTraceBailoutException extends PermanentBailoutE }; } - private SourceStackTraceBailoutException(Throwable cause, String format) { - super(cause, format); + private SourceStackTraceBailoutException(Throwable cause, String reason) { + super(cause, "%s", reason); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java index 34a7a0872ea..59ad70431e2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java @@ -42,6 +42,7 @@ import org.graalvm.compiler.lir.SwitchStrategy; import org.graalvm.compiler.lir.Variable; import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.graalvm.compiler.lir.aarch64.AArch64ArrayCompareToOp; import org.graalvm.compiler.lir.aarch64.AArch64ArrayEqualsOp; import org.graalvm.compiler.lir.aarch64.AArch64ByteSwapOp; import org.graalvm.compiler.lir.aarch64.AArch64Compare; @@ -51,13 +52,14 @@ import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp; import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp; import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp; import org.graalvm.compiler.lir.aarch64.AArch64Move; -import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp; +import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.CompareAndSwapOp; import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp; import org.graalvm.compiler.lir.aarch64.AArch64PauseOp; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGenerator; import org.graalvm.compiler.phases.util.Providers; +import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.RegisterValue; @@ -422,6 +424,21 @@ public abstract class AArch64LIRGenerator extends LIRGenerator { return result; } + @Override + public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) { + LIRKind resultKind = LIRKind.value(AArch64Kind.DWORD); + // DMS TODO: check calling conversion and registers used + RegisterValue res = AArch64.r0.asValue(resultKind); + RegisterValue cnt1 = AArch64.r1.asValue(length1.getValueKind()); + RegisterValue cnt2 = AArch64.r2.asValue(length2.getValueKind()); + emitMove(cnt1, length1); + emitMove(cnt2, length2); + append(new AArch64ArrayCompareToOp(this, kind1, kind2, res, array1, array2, cnt1, cnt2)); + Variable result = newVariable(resultKind); + emitMove(result, res); + return result; + } + @Override public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ReadNode.java similarity index 95% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadNode.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ReadNode.java index 1baec57dac2..c994367ace9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ReadNode.java @@ -22,11 +22,10 @@ * questions. */ -package org.graalvm.compiler.replacements.aarch64; +package org.graalvm.compiler.core.aarch64; import jdk.vm.ci.aarch64.AArch64Kind; -import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; -import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; + import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; @@ -42,7 +41,7 @@ import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * AArch64-specific subclass of ReadNode that knows how to merge ZeroExtend and SignExtend into the diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadReplacementPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ReadReplacementPhase.java similarity index 92% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadReplacementPhase.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ReadReplacementPhase.java index 74c909756f3..a43f119d2d4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64ReadReplacementPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ReadReplacementPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -22,7 +22,7 @@ * questions. */ -package org.graalvm.compiler.replacements.aarch64; +package org.graalvm.compiler.core.aarch64; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.StructuredGraph; @@ -46,7 +46,7 @@ public class AArch64ReadReplacementPhase extends Phase { } if (node instanceof ReadNode) { ReadNode readNode = (ReadNode) node; - if (readNode.getUsageCount() == 1) { + if (readNode.hasExactlyOneUsage()) { Node usage = readNode.getUsageAt(0); if (usage instanceof ZeroExtendNode || usage instanceof SignExtendNode) { AArch64ReadNode.replace(readNode); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java index e8b9b02bb7a..16f55481047 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64SuitesCreator.java @@ -22,14 +22,37 @@ */ package org.graalvm.compiler.core.aarch64; +import java.util.ListIterator; + import org.graalvm.compiler.java.DefaultSuitesCreator; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.phases.tiers.LowTierContext; +import org.graalvm.compiler.phases.tiers.Suites; public class AArch64SuitesCreator extends DefaultSuitesCreator { + private final Class insertReadReplacementBefore; - public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) { + public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins, Class insertReadReplacementBefore) { super(compilerConfiguration, plugins); + this.insertReadReplacementBefore = insertReadReplacementBefore; } + @Override + public Suites createSuites(OptionValues options) { + Suites suites = super.createSuites(options); + + ListIterator> findPhase = suites.getLowTier().findPhase(insertReadReplacementBefore); + // Put AArch64ReadReplacementPhase right before the SchedulePhase + while (PhaseSuite.findNextPhase(findPhase, insertReadReplacementBefore)) { + // Search for last occurrence of SchedulePhase + } + findPhase.previous(); + findPhase.add(new AArch64ReadReplacementPhase()); + return suites; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java index a0d9156a369..9984cedf942 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java @@ -26,8 +26,8 @@ package org.graalvm.compiler.core.amd64; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java index 713fe7b3fb7..f551927945f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java @@ -262,6 +262,9 @@ public final class GraalOptions { @Option(help = "Track the NodeSourcePosition.", type = OptionType.Debug) public static final OptionKey TrackNodeSourcePosition = new OptionKey<>(false); + @Option(help = "Track source stack trace where a node was inserted into the graph.", type = OptionType.Debug) + public static final OptionKey TrackNodeInsertion = new OptionKey<>(false); + @Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug) public static final OptionKey MatchExpressions = new OptionKey<>(true); @@ -276,7 +279,10 @@ public final class GraalOptions { @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug) public static final OptionKey TraceRA = new OptionKey<>(false); - @Option(help = "Enable tracing of inlining decision.", type = OptionType.Debug) + + @Option(help = "file:doc-files/TraceInliningHelp.txt", type = OptionType.Debug) public static final OptionKey TraceInlining = new OptionKey<>(false); + @Option(help = "Enable inlining decision tracing in stubs and snippets.", type = OptionType.Debug) + public static final OptionKey TraceInliningForStubsAndSnippets = new OptionKey<>(false); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java index 2e2ef19c59c..2dbffe9a7ca 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java @@ -33,7 +33,7 @@ public class PermanentBailoutException extends BailoutException { } public PermanentBailoutException(String reason) { - super(true, reason); + super(true, "%s", reason); } public PermanentBailoutException(Throwable cause, String format, Object... args) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java index 3cf6ba750c5..63875f3376e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.core.common.alloc; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.GraalOptions; import jdk.vm.ci.code.Register; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/doc-files/TraceInliningHelp.txt b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/doc-files/TraceInliningHelp.txt new file mode 100644 index 00000000000..b39aa1ce3fe --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/doc-files/TraceInliningHelp.txt @@ -0,0 +1,8 @@ +Enable tracing of inlining decisions. +Output format: + compilation of 'Signature of the compilation root method': + at 'Signature of the root method' ['Bytecode index']: <'Phase'> 'Child method signature': 'Decision made about this callsite' + at 'Signature of the child method' ['Bytecode index']: + |--<'Phase 1'> 'Grandchild method signature': 'First decision made about this callsite' + \--<'Phase 2'> 'Grandchild method signature': 'Second decision made about this callsite' + at 'Signature of the child method' ['Bytecode index']: <'Phase'> 'Another grandchild method signature': 'The only decision made about this callsite.' diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java index 63f2bfb203f..7fddd19db7f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java @@ -23,7 +23,7 @@ package org.graalvm.compiler.core.common.spi; import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.ValueKindFactory; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java index 417bb8d3415..6505accbba3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java @@ -25,8 +25,8 @@ package org.graalvm.compiler.core.common.util; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; /** * Creates an array of T objects order by the occurrence frequency of each object. The most diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java deleted file mode 100644 index 2c38dfdeba0..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.core.common.util; - -import static org.graalvm.compiler.serviceprovider.JDK9Method.JAVA_SPECIFICATION_VERSION; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import org.graalvm.compiler.debug.GraalError; - -/** - * Reflection based access to the Module API introduced by JDK 9. This allows the API to be used in - * code that must be compiled on a JDK prior to 9. Use of this class must be guarded by a test for - * JDK 9 or later. For example: - * - *

- * if (Util.JAVA_SPECIFICATION_VERSION >= 9) {
- *     // Use of ModuleAPI
- * }
- * 
- */ -public final class ModuleAPI { - - public ModuleAPI(Class declaringClass, String name, Class... parameterTypes) { - try { - this.method = declaringClass.getMethod(name, parameterTypes); - } catch (Exception e) { - throw new GraalError(e); - } - } - - public final Method method; - - public Class getReturnType() { - return method.getReturnType(); - } - - /** - * {@code Class.getModule()}. - */ - public static final ModuleAPI getModule; - - /** - * {@code java.lang.Module.getResourceAsStream(String)}. - */ - public static final ModuleAPI getResourceAsStream; - - /** - * {@code java.lang.Module.isExported(String, Module)}. - */ - public static final ModuleAPI isExportedTo; - - /** - * Invokes the static Module API method represented by this object. - */ - @SuppressWarnings("unchecked") - public T invokeStatic(Object... args) { - checkAvailability(); - assert Modifier.isStatic(method.getModifiers()); - try { - return (T) method.invoke(null, args); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new GraalError(e); - } - } - - /** - * Invokes the non-static Module API method represented by this object. - */ - @SuppressWarnings("unchecked") - public T invoke(Object receiver, Object... args) { - checkAvailability(); - assert !Modifier.isStatic(method.getModifiers()); - try { - return (T) method.invoke(receiver, args); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new GraalError(e); - } - } - - private void checkAvailability() throws GraalError { - if (method == null) { - throw new GraalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION); - } - } - - static { - if (JAVA_SPECIFICATION_VERSION >= 9) { - getModule = new ModuleAPI(Class.class, "getModule"); - Class moduleClass = getModule.getReturnType(); - getResourceAsStream = new ModuleAPI(moduleClass, "getResourceAsStream", String.class); - isExportedTo = new ModuleAPI(moduleClass, "isExported", String.class, moduleClass); - } else { - ModuleAPI unavailable = new ModuleAPI(); - getModule = unavailable; - getResourceAsStream = unavailable; - isExportedTo = unavailable; - } - } - - private ModuleAPI() { - method = null; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java index b833d296c1a..86497dc7846 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java @@ -58,9 +58,9 @@ import javax.tools.FileObject; import javax.tools.JavaFileObject; import javax.tools.StandardLocation; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.gen.NodeMatchRules; import org.graalvm.compiler.core.match.ComplexMatchResult; import org.graalvm.compiler.core.match.MatchRule; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java index 7ddf8c24b10..e9912e848c0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java @@ -80,7 +80,7 @@ import org.graalvm.compiler.phases.verify.VerifyUpdateUsages; import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals; import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage; import org.graalvm.compiler.runtime.RuntimeProvider; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import org.junit.Assert; import org.junit.Assume; import org.junit.Test; @@ -103,14 +103,6 @@ import jdk.vm.ci.meta.Value; */ public class CheckGraalInvariants extends GraalCompilerTest { - public CheckGraalInvariants() { - try { - Class.forName("java.lang.management.ManagementFactory"); - } catch (ClassNotFoundException ex) { - Assume.assumeNoException("cannot run without java.management JDK9 module", ex); - } - } - private static boolean shouldVerifyEquals(ResolvedJavaMethod m) { if (m.getName().equals("identityEquals")) { ResolvedJavaType c = m.getDeclaringClass(); @@ -148,7 +140,7 @@ public class CheckGraalInvariants extends GraalCompilerTest { } protected boolean shouldLoadClass(String className) { - return !className.equals("module-info"); + return !className.equals("module-info") && !className.startsWith("META-INF.versions."); } protected void handleClassLoadingException(Throwable t) { @@ -191,7 +183,7 @@ public class CheckGraalInvariants extends GraalCompilerTest { for (final Enumeration entry = zipFile.entries(); entry.hasMoreElements();) { final ZipEntry zipEntry = entry.nextElement(); String name = zipEntry.getName(); - if (name.endsWith(".class")) { + if (name.endsWith(".class") && !name.startsWith("META-INF/versions/")) { String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); if (isInNativeImage(className)) { /* diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java index 557d6ac67d9..96952422668 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java @@ -27,7 +27,7 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java index b90e5a0f4a3..10c16e8d039 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.core.test; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Scope; import org.graalvm.compiler.debug.DebugOptions; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java index db994ec410e..86baed4cbc6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java @@ -26,8 +26,6 @@ import static org.graalvm.compiler.core.GraalCompiler.compileGraph; import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions; import static org.junit.Assert.assertNotNull; -import org.junit.Test; - import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.nodes.FullInfopointNode; @@ -37,6 +35,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Test; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.Infopoint; @@ -50,6 +49,11 @@ public class InfopointReasonTest extends GraalCompilerTest { public static final String[] STRINGS = new String[]{"world", "everyone", "you"}; + public InfopointReasonTest() { + // Call testMethod to ensure all method references are resolved. + testMethod(); + } + public String testMethod() { StringBuilder sb = new StringBuilder("Hello "); for (String s : STRINGS) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java index 2e747addf82..e04859f40b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,6 +116,7 @@ public class MarkUnsafeAccessTest extends GraalCompilerTest { @Test public void testCompiled() throws IOException { + Assume.assumeFalse("Crashes on AArch64 (GR-8351)", System.getProperty("os.arch").equalsIgnoreCase("aarch64")); ResolvedJavaMethod getMethod = asResolvedJavaMethod(getMethod(ByteBuffer.class, "get", new Class[]{})); ResolvedJavaType mbbClass = getMetaAccess().lookupJavaType(MappedByteBuffer.class); ResolvedJavaMethod getMethodImpl = mbbClass.findUniqueConcreteMethod(getMethod).getResult(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java index 22b7b3f7676..f0290578fee 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java @@ -33,7 +33,7 @@ import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.nodes.FieldLocationIdentity; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.memory.Access; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.ResolvedJavaField; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java index 47532f95132..01f3d3c42c0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java @@ -31,12 +31,13 @@ import java.util.Iterator; import java.util.Map; import java.util.Properties; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; /** @@ -108,8 +109,8 @@ public class ReflectionOptionDescriptors implements OptionDescriptors { ParameterizedType pt = (ParameterizedType) declaredType; Type[] actualTypeArguments = pt.getActualTypeArguments(); assert actualTypeArguments.length == 1; - Class optionType = (Class) actualTypeArguments[0]; - descriptors.put(fieldName, OptionDescriptor.create(fieldName, optionType, help, declaringClass, fieldName, (OptionKey) f.get(null))); + Class optionValueType = (Class) actualTypeArguments[0]; + descriptors.put(fieldName, OptionDescriptor.create(fieldName, OptionType.Debug, optionValueType, help, declaringClass, fieldName, (OptionKey) f.get(null))); } catch (IllegalAccessException | NoSuchFieldException e) { throw new IllegalArgumentException(e); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java index 5cbd3a3434b..61d984d4a40 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.core.test; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; -import org.junit.Ignore; import org.junit.Test; import jdk.vm.ci.meta.JavaConstant; @@ -36,21 +35,23 @@ import jdk.vm.ci.meta.MemoryAccessProvider; */ public class StampMemoryAccessTest extends GraalCompilerTest { - @Ignore("not all JVMCI versions are safe yet") @Test public void testReadPrimitive() { MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider(); - JavaConstant base = getSnippetReflection().forObject(""); Stamp stamp = StampFactory.forKind(JavaKind.Long); - assertTrue(stamp.readConstant(memory, base, 128) == null); + JavaConstant objectBase = getSnippetReflection().forObject(""); + assertTrue(stamp.readConstant(memory, objectBase, 128) == null); + JavaConstant arrayBase = getSnippetReflection().forObject(new int[]{}); + assertTrue(stamp.readConstant(memory, arrayBase, 128) == null); } - @Ignore("not all JVMCI versions are safe yet") @Test public void testReadObject() { MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider(); - JavaConstant base = getSnippetReflection().forObject(""); Stamp stamp = StampFactory.forKind(JavaKind.Object); - assertTrue(stamp.readConstant(memory, base, 128) == null); + JavaConstant objectBase = getSnippetReflection().forObject(""); + assertTrue(stamp.readConstant(memory, objectBase, 128) == null); + JavaConstant arrayBase = getSnippetReflection().forObject(new int[]{}); + assertTrue(stamp.readConstant(memory, arrayBase, 128) == null); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java index 3af2ec92d7c..5f1552c2668 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java @@ -39,6 +39,7 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; import jdk.vm.ci.meta.JavaConstant; @@ -405,6 +406,8 @@ public class EscapeAnalysisTest extends EATestBase { */ @Test public void testNewNode() { + // Trackking of creation interferes with escape analysis + Assume.assumeFalse(Node.TRACK_CREATION_POSITION); testEscapeAnalysis("testNewNodeSnippet", null, false); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java index 7d6e97b23a4..ccfbbf37720 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java @@ -22,9 +22,11 @@ */ package org.graalvm.compiler.core.test.inlining; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.FullInfopointNode; import org.graalvm.compiler.nodes.Invoke; @@ -32,18 +34,22 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.StructuredGraph.Builder; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import jdk.vm.ci.code.site.InfopointReason; import jdk.vm.ci.meta.ResolvedJavaMethod; +import java.util.regex.Pattern; + public class InliningTest extends GraalCompilerTest { @Test @@ -198,6 +204,40 @@ public class InliningTest extends GraalCompilerTest { assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", true))); } + public static void traceInliningTest() { + callTrivial(); + } + + private static void callTrivial() { + callNonTrivial(); + } + + private static double callNonTrivial() { + double x = 0.0; + for (int i = 0; i < 10; i++) { + x += i * 1.21; + } + return x; + } + + @Test + @SuppressWarnings("try") + public void testTracing() { + OptionValues options = new OptionValues(getInitialOptions(), GraalOptions.TraceInlining, true); + StructuredGraph graph; + try (TTY.Filter f = new TTY.Filter()) { + graph = getGraph("traceInliningTest", options, false); + } + String inliningTree = graph.getInliningLog().formatAsTree(false); + String expectedRegex = "compilation of org.graalvm.compiler.core.test.inlining.InliningTest.traceInliningTest.*: \\R" + + " at .*org.graalvm.compiler.core.test.inlining.InliningTest.traceInliningTest.*: org.graalvm.compiler.core.test.inlining.InliningTest.callTrivial.*: yes, inline method\\R" + + " at .*org.graalvm.compiler.core.test.inlining.InliningTest.callTrivial.*: .*\\R" + + " .* org.graalvm.compiler.core.test.inlining.InliningTest.callNonTrivial.*: .*(.*\\R)*" + + " .* org.graalvm.compiler.core.test.inlining.InliningTest.callNonTrivial.*: .*(.*\\R)*"; + Pattern expectedPattern = Pattern.compile(expectedRegex, Pattern.MULTILINE); + Assert.assertTrue("Got: " + inliningTree, expectedPattern.matcher(inliningTree).matches()); + } + @SuppressWarnings("all") public static int invokeLeafClassMethodSnippet(SubClassA subClassA) { return subClassA.publicFinalMethod() + subClassA.publicNotOverriddenMethod() + subClassA.publicOverriddenMethod(); @@ -233,9 +273,13 @@ public class InliningTest extends GraalCompilerTest { return superClass.protectedOverriddenMethod(); } - @SuppressWarnings("try") private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) { - DebugContext debug = getDebugContext(); + return getGraph(snippet, null, eagerInfopointMode); + } + + @SuppressWarnings("try") + private StructuredGraph getGraph(final String snippet, OptionValues options, final boolean eagerInfopointMode) { + DebugContext debug = options == null ? getDebugContext() : getDebugContext(options, null, null); try (DebugContext.Scope s = debug.scope("InliningTest", new DebugDumpScope(snippet, true))) { ResolvedJavaMethod method = getResolvedJavaMethod(snippet); Builder builder = builder(method, AllowAssumptions.YES, debug); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java index b1dc8ae1fc2..9d9fa8f1996 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.core.test.inlining; import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.TTY; @@ -137,7 +137,8 @@ public class NestedLoopEffectsPhaseComplexityTest extends GraalCompilerTest { ResolvedJavaMethod calleeMethod = next.callTarget().targetMethod(); for (int i = 0; i < inliningCount; i++) { next = callerGraph.getNodes(MethodCallTargetNode.TYPE).first().invoke(); - EconomicSet canonicalizeNodes = InliningUtil.inlineForCanonicalization(next, calleeGraph, false, calleeMethod); + EconomicSet canonicalizeNodes = InliningUtil.inlineForCanonicalization(next, calleeGraph, false, calleeMethod, null, + "Called explicitly from a unit test.", "Test case"); canonicalizer.applyIncremental(callerGraph, context, canonicalizeNodes); callerGraph.getDebug().dump(DebugContext.DETAILED_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java index f7ca6604c51..649963a5ffb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationPrinter.java @@ -23,10 +23,11 @@ package org.graalvm.compiler.core; import static org.graalvm.compiler.core.GraalCompilerOptions.PrintCompilation; +import static org.graalvm.compiler.serviceprovider.GraalServices.getCurrentThreadAllocatedBytes; +import static org.graalvm.compiler.serviceprovider.GraalServices.isThreadAllocatedMemorySupported; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompilationIdentifier; -import org.graalvm.compiler.debug.Management; import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.options.OptionValues; @@ -58,11 +59,6 @@ public final class CompilationPrinter { */ public static CompilationPrinter begin(OptionValues options, CompilationIdentifier id, JavaMethod method, int entryBCI) { if (PrintCompilation.getValue(options) && !TTY.isSuppressed()) { - try { - Class.forName("java.lang.management.ManagementFactory"); - } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException("PrintCompilation option requires java.management module"); - } return new CompilationPrinter(id, method, entryBCI); } return DISABLED; @@ -83,9 +79,8 @@ public final class CompilationPrinter { this.id = id; this.entryBCI = entryBCI; - final long threadId = Thread.currentThread().getId(); start = System.nanoTime(); - allocatedBytesBefore = getAllocatedBytes(threadId); + allocatedBytesBefore = isThreadAllocatedMemorySupported() ? getCurrentThreadAllocatedBytes() : -1; } private String getMethodDescription() { @@ -101,24 +96,17 @@ public final class CompilationPrinter { */ public void finish(CompilationResult result) { if (id != null) { - final long threadId = Thread.currentThread().getId(); final long stop = System.nanoTime(); final long duration = (stop - start) / 1000000; final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; final int bytecodeSize = result != null ? result.getBytecodeSize() : 0; - final long allocatedBytesAfter = getAllocatedBytes(threadId); - final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; - - TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); + if (allocatedBytesBefore == -1) { + TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB", duration, bytecodeSize, targetCodeSize)); + } else { + final long allocatedBytesAfter = getCurrentThreadAllocatedBytes(); + final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; + TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); + } } } - - static com.sun.management.ThreadMXBean threadMXBean; - - static long getAllocatedBytes(long threadId) { - if (threadMXBean == null) { - threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean(); - } - return threadMXBean.getThreadAllocatedBytes(threadId); - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java index 2b5c32aaccd..74bfa44878d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java @@ -122,8 +122,10 @@ public abstract class CompilationWrapper { * * Subclasses can override this to choose a different action based on factors such as whether * {@code actionKey} has been explicitly set in {@code options} for example. + * + * @param cause the cause of the bailout or failure */ - protected ExceptionAction lookupAction(OptionValues options, EnumOptionKey actionKey) { + protected ExceptionAction lookupAction(OptionValues options, EnumOptionKey actionKey, Throwable cause) { if (actionKey == CompilationFailureAction) { if (ExitVMOnException.getValue(options)) { assert CompilationFailureAction.getDefaultValue() != ExceptionAction.ExitVM; @@ -175,7 +177,7 @@ public abstract class CompilationWrapper { actionKey = CompilationFailureAction; causeType = "failure"; } - ExceptionAction action = lookupAction(initialOptions, actionKey); + ExceptionAction action = lookupAction(initialOptions, actionKey, cause); action = adjustAction(initialOptions, actionKey, action); @@ -262,22 +264,34 @@ public abstract class CompilationWrapper { DumpPath, dumpPath.getPath()); try (DebugContext retryDebug = createRetryDebugContext(retryOptions)) { - return performCompilation(retryDebug); + T res = performCompilation(retryDebug); + maybeExitVM(action); + return res; } catch (Throwable ignore) { // Failures during retry are silent - return handleException(cause); - } finally { - if (action == ExitVM) { - synchronized (ExceptionAction.class) { - TTY.println("Exiting VM after retry compilation of " + this); - System.exit(-1); - } - } + T res = handleException(cause); + maybeExitVM(action); + return res; } } } } + private void maybeExitVM(ExceptionAction action) { + if (action == ExitVM) { + synchronized (ExceptionAction.class) { + try { + // Give other compiler threads a chance to flush + // error handling output. + ExceptionAction.class.wait(2000); + } catch (InterruptedException e) { + } + TTY.println("Exiting VM after retry compilation of " + this); + System.exit(-1); + } + } + } + /** * Adjusts {@code initialAction} if necessary based on * {@link GraalCompilerOptions#MaxCompilationProblemsPerAction}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java index 093e0ab38e2..047b5d2fa90 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java @@ -25,10 +25,12 @@ package org.graalvm.compiler.core; import java.util.Collection; import java.util.List; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext; import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.RetryableBailoutException; import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; @@ -188,8 +190,18 @@ public class GraalCompiler { * {@code graph.method()} or {@code graph.name} */ private static void checkForRequestedCrash(StructuredGraph graph) { - String methodPattern = GraalCompilerOptions.CrashAt.getValue(graph.getOptions()); - if (methodPattern != null) { + String value = GraalCompilerOptions.CrashAt.getValue(graph.getOptions()); + if (value != null) { + boolean bailout = false; + boolean permanentBailout = false; + String methodPattern = value; + if (value.endsWith(":Bailout")) { + methodPattern = value.substring(0, value.length() - ":Bailout".length()); + bailout = true; + } else if (value.endsWith(":PermanentBailout")) { + methodPattern = value.substring(0, value.length() - ":PermanentBailout".length()); + permanentBailout = true; + } String crashLabel = null; if (graph.name != null && graph.name.contains(methodPattern)) { crashLabel = graph.name; @@ -204,6 +216,12 @@ public class GraalCompiler { } } if (crashLabel != null) { + if (permanentBailout) { + throw new PermanentBailoutException("Forced crash after compiling " + crashLabel); + } + if (bailout) { + throw new RetryableBailoutException("Forced crash after compiling " + crashLabel); + } throw new RuntimeException("Forced crash after compiling " + crashLabel); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java index f19c83ac810..a07bb8a814a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java @@ -38,12 +38,14 @@ public class GraalCompilerOptions { public static final OptionKey PrintCompilation = new OptionKey<>(false); @Option(help = "Pattern for method(s) that will trigger an exception when compiled. " + "This option exists to test handling compilation crashes gracefully. " + - "See the MethodFilter option for the pattern syntax. ", type = OptionType.Debug) + "See the MethodFilter option for the pattern syntax. A ':Bailout' " + + "suffix will raise a bailout exception and a ':PermanentBailout' " + + "suffix will raise a permanent bailout exception.", type = OptionType.Debug) public static final OptionKey CrashAt = new OptionKey<>(null); @Option(help = "file:doc-files/CompilationBailoutActionHelp.txt", type = OptionType.User) public static final EnumOptionKey CompilationBailoutAction = new EnumOptionKey<>(ExceptionAction.Silent); @Option(help = "Specifies the action to take when compilation fails with a bailout exception. " + - "The accepted values are the same as for CompilationBailoutAction.", type = OptionType.User) + "The accepted values are the same as for CompilationBailoutAction.", type = OptionType.User) public static final EnumOptionKey CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose); @Option(help = "The maximum number of compilation failures or bailouts to handle with the action specified " + "by CompilationFailureAction or CompilationBailoutAction before changing to a less verbose action.", type = OptionType.User) diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java index 9d5a5a331ef..e3c205d0bc3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java @@ -26,8 +26,8 @@ import java.util.ArrayDeque; import java.util.Arrays; import java.util.Queue; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java index 7091847e552..fd51775df81 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java @@ -33,8 +33,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java index c56e908d8d5..c977029cae5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java @@ -28,8 +28,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.gen.NodeLIRBuilder; import org.graalvm.compiler.core.match.MatchPattern.Result; import org.graalvm.compiler.debug.DebugContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java index 88bf3d41b4c..0d9e5738f03 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java @@ -27,9 +27,9 @@ import static org.graalvm.compiler.debug.DebugOptions.LogVerbose; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.core.gen.NodeMatchRules; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CommunityCompilerConfiguration.java similarity index 95% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CommunityCompilerConfiguration.java index d714edea6a4..03d690fa81e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CoreCompilerConfiguration.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CommunityCompilerConfiguration.java @@ -36,7 +36,10 @@ import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.LowTierContext; import org.graalvm.compiler.phases.tiers.MidTierContext; -public class CoreCompilerConfiguration implements CompilerConfiguration { +/** + * The default configuration for the community edition of Graal. + */ +public class CommunityCompilerConfiguration implements CompilerConfiguration { @Override public PhaseSuite createHighTier(OptionValues options) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java index 12fc5f99dae..88219dba52b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyCompilerConfiguration.java @@ -36,6 +36,10 @@ import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.LowTierContext; import org.graalvm.compiler.phases.tiers.MidTierContext; +/** + * A compiler configuration that performs fewer Graal IR optimizations while using the same backend + * as the {@link CommunityCompilerConfiguration}. + */ public class EconomyCompilerConfiguration implements CompilerConfiguration { @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java index 90b32495f18..26cce87e19a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.core.phases; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Graph.NodeEvent; import org.graalvm.compiler.graph.Graph.NodeEventScope; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java index 9c4921683e6..523b0be10f2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.core.target; import java.util.ArrayList; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompilationIdentifier; @@ -41,6 +41,7 @@ import org.graalvm.compiler.lir.framemap.FrameMapBuilder; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.GraphSpeculationLog; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.phases.tiers.SuitesProvider; import org.graalvm.compiler.phases.tiers.TargetProvider; @@ -209,7 +210,7 @@ public abstract class Backend implements TargetProvider, ValueKindFactory= ms) { return durationMS; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java index 29137335526..da7d92569a9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.debug; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; class CounterKeyImpl extends AbstractKey implements CounterKey { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java index 65a9833624d..07d0cbfa63e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java @@ -264,9 +264,8 @@ final class DebugConfigImpl implements DebugConfig { firstSeen.put(o, o); if (DebugOptions.DumpOnError.getValue(options) || DebugOptions.Dump.getValue(options) != null) { debug.dump(DebugContext.BASIC_LEVEL, o, "Exception: %s", e); - } else { - debug.log("Context obj %s", o); } + debug.log("Context obj %s", o); } } } finally { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java index f358e8490d3..183916eca54 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java @@ -56,11 +56,12 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.graphio.GraphOutput; import jdk.vm.ci.meta.JavaMethod; @@ -236,14 +237,15 @@ public final class DebugContext implements AutoCloseable { this.unscopedTimers = parseUnscopedMetricSpec(Timers.getValue(options), "".equals(timeValue), true); this.unscopedMemUseTrackers = parseUnscopedMetricSpec(MemUseTrackers.getValue(options), "".equals(trackMemUseValue), true); - if (unscopedTimers != null || - unscopedMemUseTrackers != null || - timeValue != null || - trackMemUseValue != null) { - try { - Class.forName("java.lang.management.ManagementFactory"); - } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException("Time, Timers, MemUseTrackers and TrackMemUse options require java.management module"); + if (unscopedTimers != null || timeValue != null) { + if (!GraalServices.isCurrentThreadCpuTimeSupported()) { + throw new IllegalArgumentException("Time and Timers options require VM support for querying CPU time"); + } + } + + if (unscopedMemUseTrackers != null || trackMemUseValue != null) { + if (!GraalServices.isThreadAllocatedMemorySupported()) { + throw new IllegalArgumentException("MemUseTrackers and TrackMemUse options require VM support for querying thread allocated memory"); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java index b509ccbfc8f..3fe442ecf96 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java @@ -27,11 +27,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; /** * Options that configure a {@link DebugContext} and related functionality. @@ -133,9 +134,7 @@ public class DebugOptions { @Option(help = "Host part of the address to which graphs are dumped.", type = OptionType.Debug) public static final OptionKey PrintGraphHost = new OptionKey<>("127.0.0.1"); - @Option(help = "Port part of the address to which graphs are dumped in XML format (ignored if PrintBinaryGraphs=true).", type = OptionType.Debug) - public static final OptionKey PrintXmlGraphPort = new OptionKey<>(4444); - @Option(help = "Port part of the address to which graphs are dumped in binary format (ignored if PrintBinaryGraphs=false).", type = OptionType.Debug) + @Option(help = "Port part of the address to which graphs are dumped in binary format.", type = OptionType.Debug) public static final OptionKey PrintBinaryGraphPort = new OptionKey<>(4445); @Option(help = "Schedule graphs as they are dumped.", type = OptionType.Debug) public static final OptionKey PrintGraphWithSchedule = new OptionKey<>(false); @@ -164,23 +163,10 @@ public class DebugOptions { @Option(help = "Do not compile anything on bootstrap but just initialize the compiler.", type = OptionType.Debug) public static final OptionKey BootstrapInitializeOnly = new OptionKey<>(false); - // These will be removed at some point - @Option(help = "Deprecated - use PrintGraphHost instead.", type = OptionType.Debug) - static final OptionKey PrintIdealGraphAddress = new DebugOptions.DeprecatedOptionKey<>(PrintGraphHost); - @Option(help = "Deprecated - use PrintGraphWithSchedule instead.", type = OptionType.Debug) - static final OptionKey PrintIdealGraphSchedule = new DebugOptions.DeprecatedOptionKey<>(PrintGraphWithSchedule); - @Option(help = "Deprecated - use PrintGraph instead.", type = OptionType.Debug) - static final OptionKey PrintIdealGraph = new DebugOptions.DeprecatedOptionKey<>(PrintGraph); - @Option(help = "Deprecated - use PrintGraphFile instead.", type = OptionType.Debug) - static final OptionKey PrintIdealGraphFile = new DebugOptions.DeprecatedOptionKey<>(PrintGraphFile); - @Option(help = "Deprecated - use PrintXmlGraphPort instead.", type = OptionType.Debug) - static final OptionKey PrintIdealGraphPort = new DebugOptions.DeprecatedOptionKey<>(PrintXmlGraphPort); - // @formatter:on - /** * Gets the directory in which {@link DebugDumpHandler}s can generate output. This will be the * directory specified by {@link #DumpPath} if it has been set otherwise it will be derived from - * the default value of {@link #DumpPath} and {@link PathUtilities#getGlobalTimeStamp()}. + * the default value of {@link #DumpPath} and {@link GraalServices#getGlobalTimeStamp()}. * * This method will ensure the returned directory exists, printing a message to {@link TTY} if * it creates it. @@ -193,14 +179,16 @@ public class DebugOptions { if (DumpPath.hasBeenSet(options)) { dumpDir = Paths.get(DumpPath.getValue(options)); } else { - dumpDir = Paths.get(DumpPath.getValue(options), String.valueOf(PathUtilities.getGlobalTimeStamp())); + dumpDir = Paths.get(DumpPath.getValue(options), String.valueOf(GraalServices.getGlobalTimeStamp())); } dumpDir = dumpDir.toAbsolutePath(); if (!Files.exists(dumpDir)) { synchronized (DebugConfigImpl.class) { if (!Files.exists(dumpDir)) { Files.createDirectories(dumpDir); - TTY.println("Dumping debug output in %s", dumpDir.toString()); + if (ShowDumpFiles.getValue(options)) { + TTY.println("Dumping debug output in %s", dumpDir.toString()); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java index 377ba003579..769a72499c8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java @@ -39,6 +39,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; /** * Manages a directory into which diagnostics such crash reports and dumps should be written. The @@ -69,26 +70,6 @@ public class DiagnosticsOutputDirectory { return getPath(true); } - /** - * Gets a unique identifier for this execution such as a process ID. - */ - protected String getExecutionID() { - try { - String runtimeName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); - try { - int index = runtimeName.indexOf('@'); - if (index != -1) { - long pid = Long.parseLong(runtimeName.substring(0, index)); - return Long.toString(pid); - } - } catch (NumberFormatException e) { - } - return runtimeName; - } catch (LinkageError err) { - return String.valueOf(org.graalvm.compiler.debug.PathUtilities.getGlobalTimeStamp()); - } - } - private synchronized String getPath(boolean createIfNull) { if (path == null && createIfNull) { path = createPath(); @@ -120,7 +101,7 @@ public class DiagnosticsOutputDirectory { // directory specified by the DumpPath option. baseDir = Paths.get("."); } - return baseDir.resolve("graal_diagnostics_" + getExecutionID()).toAbsolutePath().toString(); + return baseDir.resolve("graal_diagnostics_" + GraalServices.getExecutionID()).toAbsolutePath().toString(); } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java index 62518d12b29..bc4c1f57516 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java @@ -29,9 +29,9 @@ import java.nio.file.Paths; import java.util.Collections; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.options.OptionValues; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java index d7814f5a379..bfd72434bf8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.debug; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; /** * Registry for allocating a globally unique integer id to each {@link AbstractKey}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java deleted file mode 100644 index 0ea5d76eced..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Management.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2015, 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 org.graalvm.compiler.debug; - -import static java.lang.Thread.currentThread; - -public class Management { - - private static final com.sun.management.ThreadMXBean threadMXBean = Management.initThreadMXBean(); - - /** - * The amount of memory allocated by - * {@link com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long)} itself. - */ - private static final long threadMXBeanOverhead = -getCurrentThreadAllocatedBytes() + getCurrentThreadAllocatedBytes(); - - public static long getCurrentThreadAllocatedBytes() { - return threadMXBean.getThreadAllocatedBytes(currentThread().getId()) - threadMXBeanOverhead; - } - - private static com.sun.management.ThreadMXBean initThreadMXBean() { - try { - return (com.sun.management.ThreadMXBean) java.lang.management.ManagementFactory.getThreadMXBean(); - } catch (Error err) { - return new UnimplementedBean(); - } - } - - public static java.lang.management.ThreadMXBean getThreadMXBean() { - return threadMXBean; - } - - private static class UnimplementedBean implements java.lang.management.ThreadMXBean, com.sun.management.ThreadMXBean { - - @Override - public javax.management.ObjectName getObjectName() { - return null; - } - - @Override - public long getThreadAllocatedBytes(long arg0) { - return 0; - } - - @Override - public long[] getThreadAllocatedBytes(long[] arg0) { - return null; - } - - @Override - public long[] getThreadCpuTime(long[] arg0) { - return null; - } - - @Override - public long[] getThreadUserTime(long[] arg0) { - return null; - } - - @Override - public boolean isThreadAllocatedMemoryEnabled() { - return false; - } - - @Override - public boolean isThreadAllocatedMemorySupported() { - return false; - } - - @Override - public void setThreadAllocatedMemoryEnabled(boolean arg0) { - } - - @Override - public int getThreadCount() { - return 0; - } - - @Override - public int getPeakThreadCount() { - return 0; - } - - @Override - public long getTotalStartedThreadCount() { - return 0; - } - - @Override - public int getDaemonThreadCount() { - return 0; - } - - @Override - public long[] getAllThreadIds() { - return null; - } - - @Override - public java.lang.management.ThreadInfo getThreadInfo(long id) { - return null; - } - - @Override - public java.lang.management.ThreadInfo[] getThreadInfo(long[] ids) { - return null; - } - - @Override - public java.lang.management.ThreadInfo getThreadInfo(long id, int maxDepth) { - return null; - } - - @Override - public java.lang.management.ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) { - return null; - } - - @Override - public boolean isThreadContentionMonitoringSupported() { - return false; - } - - @Override - public boolean isThreadContentionMonitoringEnabled() { - return false; - } - - @Override - public void setThreadContentionMonitoringEnabled(boolean enable) { - } - - @Override - public long getCurrentThreadCpuTime() { - return 0; - } - - @Override - public long getCurrentThreadUserTime() { - return 0; - } - - @Override - public long getThreadCpuTime(long id) { - return 0; - } - - @Override - public long getThreadUserTime(long id) { - return 0; - } - - @Override - public boolean isThreadCpuTimeSupported() { - return false; - } - - @Override - public boolean isCurrentThreadCpuTimeSupported() { - return false; - } - - @Override - public boolean isThreadCpuTimeEnabled() { - return false; - } - - @Override - public void setThreadCpuTimeEnabled(boolean enable) { - } - - @Override - public long[] findMonitorDeadlockedThreads() { - return null; - } - - @Override - public void resetPeakThreadCount() { - } - - @Override - public long[] findDeadlockedThreads() { - return null; - } - - @Override - public boolean isObjectMonitorUsageSupported() { - return false; - } - - @Override - public boolean isSynchronizerUsageSupported() { - return false; - } - - @Override - public java.lang.management.ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) { - return null; - } - - @Override - public java.lang.management.ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) { - return null; - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java index 9b6f238efd3..1998e8dfe5f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.debug; +import org.graalvm.compiler.serviceprovider.GraalServices; + /** * Tracks memory usage within a scope using {@link com.sun.management.ThreadMXBean}. This facility * should be employed using the try-with-resources pattern: @@ -52,6 +54,6 @@ public interface MemUseTrackerKey extends MetricKey { MemUseTrackerKey doc(String string); static long getCurrentThreadAllocatedBytes() { - return Management.getCurrentThreadAllocatedBytes(); + return GraalServices.getCurrentThreadAllocatedBytes(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java index c61ea727999..641006eeb50 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.debug; import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; class MemUseTrackerKeyImpl extends AccumulatedKey implements MemUseTrackerKey { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java index eea896ad392..394119de4d0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.debug; import java.util.Comparator; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; /** * A key for a metric. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java index e9f1e216faf..45af5e12981 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java @@ -29,7 +29,6 @@ import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.concurrent.atomic.AtomicLong; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; @@ -39,19 +38,6 @@ import org.graalvm.compiler.options.OptionValues; */ public class PathUtilities { - private static final AtomicLong globalTimeStamp = new AtomicLong(); - - /** - * Gets a time stamp for the current process. This method will always return the same value for - * the current VM execution. - */ - public static long getGlobalTimeStamp() { - if (globalTimeStamp.get() == 0) { - globalTimeStamp.compareAndSet(0, System.currentTimeMillis()); - } - return globalTimeStamp.get(); - } - /** * Gets a value based on {@code name} that can be passed to {@link Paths#get(String, String...)} * without causing an {@link InvalidPathException}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java index 1f0d98e23f7..25c094f44ec 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimeSource.java @@ -22,21 +22,13 @@ */ package org.graalvm.compiler.debug; +import org.graalvm.compiler.serviceprovider.GraalServices; + /** * A consistent source of timing data that should be used by all facilities in the debug package. */ public class TimeSource { - private static final boolean USING_BEAN; - private static final java.lang.management.ThreadMXBean threadMXBean; - - static { - threadMXBean = Management.getThreadMXBean(); - if (threadMXBean.isThreadCpuTimeSupported()) { - USING_BEAN = true; - } else { - USING_BEAN = false; - } - } + private static final boolean USING_THREAD_CPU_TIME = GraalServices.isCurrentThreadCpuTimeSupported(); /** * Gets the current time of this thread in nanoseconds from the most accurate timer available on @@ -50,7 +42,7 @@ public class TimeSource { * @return the current thread's time in nanoseconds */ public static long getTimeNS() { - return USING_BEAN ? threadMXBean.getCurrentThreadCpuTime() : System.nanoTime(); + return USING_THREAD_CPU_TIME ? GraalServices.getCurrentThreadCpuTime() : System.nanoTime(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java index 0e17d0053ad..76dadad7621 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java @@ -26,7 +26,7 @@ import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE; import java.util.concurrent.TimeUnit; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; final class TimerKeyImpl extends AccumulatedKey implements TimerKey { static class FlatTimer extends AbstractKey implements TimerKey { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml deleted file mode 100644 index 3f8eca7f6f4..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml +++ /dev/null @@ -1,241 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java index 320b0fdd381..ae2aaaa7390 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.graph; import java.util.function.Consumer; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; /** * This class is a container of a graph that needs to be readonly and optionally a lazily created diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java index 1151396955b..482de328b49 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.graph; +import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeInsertion; import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Default; import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Track; import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.UpdateOnly; @@ -33,15 +34,16 @@ import java.util.Arrays; import java.util.Iterator; import java.util.function.Consumer; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TimerKey; +import org.graalvm.compiler.graph.Node.NodeInsertionStackTrace; import org.graalvm.compiler.graph.Node.ValueNumberable; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.options.Option; @@ -49,6 +51,8 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; +import jdk.vm.ci.meta.ResolvedJavaMethod; + /** * This class is a graph container, it contains the set of nodes that belong to this graph. */ @@ -195,7 +199,7 @@ public class Graph { * was opened */ public DebugCloseable withNodeSourcePosition(Node node) { - return withNodeSourcePosition(node.sourcePosition); + return withNodeSourcePosition(node.getNodeSourcePosition()); } /** @@ -719,6 +723,9 @@ public class Graph { assert node.getNodeClass().valueNumberable(); T other = this.findDuplicate(node); if (other != null) { + if (other.getNodeSourcePosition() == null) { + other.setNodeSourcePosition(node.getNodeSourcePosition()); + } return other; } else { T result = addHelper(node); @@ -1097,6 +1104,9 @@ public class Graph { if (currentNodeSourcePosition != null && trackNodeSourcePosition()) { node.setNodeSourcePosition(currentNodeSourcePosition); } + if (TrackNodeInsertion.getValue(getOptions())) { + node.setInsertionPosition(new NodeInsertionStackTrace()); + } updateNodeCaches(node); @@ -1189,6 +1199,23 @@ public class Graph { return true; } + public boolean verifySourcePositions() { + if (trackNodeSourcePosition()) { + ResolvedJavaMethod root = null; + for (Node node : getNodes()) { + NodeSourcePosition pos = node.getNodeSourcePosition(); + if (pos != null) { + if (root == null) { + root = pos.getRootMethod(); + } else { + assert pos.verifyRootMethod(root) : node; + } + } + } + } + return true; + } + public Node getNode(int id) { return nodes[id]; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java index 2dd4131de83..850eb49bd42 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java @@ -29,6 +29,7 @@ import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE; import java.lang.annotation.ElementType; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.Formattable; @@ -84,7 +85,8 @@ import sun.misc.Unsafe; public abstract class Node implements Cloneable, Formattable, NodeInterface { public static final NodeClass TYPE = null; - public static final boolean USE_UNSAFE_TO_CLONE = true; + + public static final boolean TRACK_CREATION_POSITION = Boolean.getBoolean("debug.graal.TrackNodeCreationPosition"); static final int DELETED_ID_START = -1000000000; static final int INITIAL_ID = -1; @@ -230,6 +232,40 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { public static final int NODE_LIST = -2; public static final int NOT_ITERABLE = -1; + static class NodeStackTrace { + final StackTraceElement[] stackTrace; + + NodeStackTrace() { + this.stackTrace = new Throwable().getStackTrace(); + } + + private String getString(String label) { + StringBuilder sb = new StringBuilder(); + if (label != null) { + sb.append(label).append(": "); + } + for (StackTraceElement ste : stackTrace) { + sb.append("at ").append(ste.toString()).append('\n'); + } + return sb.toString(); + } + + String getStrackTraceString() { + return getString(null); + } + + @Override + public String toString() { + return getString(getClass().getSimpleName()); + } + } + + static class NodeCreationStackTrace extends NodeStackTrace { + } + + static class NodeInsertionStackTrace extends NodeStackTrace { + } + public Node(NodeClass c) { init(c); } @@ -239,6 +275,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { this.nodeClass = c; id = INITIAL_ID; extraUsages = NO_NODES; + if (TRACK_CREATION_POSITION) { + setCreationPosition(new NodeCreationStackTrace()); + } } final int id() { @@ -577,32 +616,95 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { } /** - * The position of the bytecode that generated this node. + * Information associated with this node. A single value is stored directly in the field. + * Multiple values are stored by creating an Object[]. */ - NodeSourcePosition sourcePosition; + private Object annotation; + + private T getNodeInfo(Class clazz) { + assert clazz != Object[].class; + if (annotation == null) { + return null; + } + if (clazz.isInstance(annotation)) { + return clazz.cast(annotation); + } + if (annotation.getClass() == Object[].class) { + Object[] annotations = (Object[]) annotation; + for (Object ann : annotations) { + if (clazz.isInstance(ann)) { + return clazz.cast(ann); + } + } + } + return null; + } + + private void setNodeInfo(Class clazz, T value) { + assert clazz != Object[].class; + if (annotation == null || clazz.isInstance(annotation)) { + // Replace the current value + this.annotation = value; + } else if (annotation.getClass() == Object[].class) { + Object[] annotations = (Object[]) annotation; + for (int i = 0; i < annotations.length; i++) { + if (clazz.isInstance(annotations[i])) { + annotations[i] = value; + return; + } + } + Object[] newAnnotations = Arrays.copyOf(annotations, annotations.length + 1); + newAnnotations[annotations.length] = value; + this.annotation = newAnnotations; + } else { + this.annotation = new Object[]{this.annotation, value}; + } + } /** * Gets the source position information for this node or null if it doesn't exist. */ public NodeSourcePosition getNodeSourcePosition() { - return sourcePosition; + return getNodeInfo(NodeSourcePosition.class); } /** - * Set the source position to {@code sourcePosition}. + * Set the source position to {@code sourcePosition}. Setting it to null is ignored so that it's + * not accidentally cleared. Use {@link #clearNodeSourcePosition()} instead. */ public void setNodeSourcePosition(NodeSourcePosition sourcePosition) { - assert sourcePosition != null || this.sourcePosition == null || this.sourcePosition.isPlaceholder() : "Invalid source position at node with id " + id; - this.sourcePosition = sourcePosition; - // assert sourcePosition == null || graph == null || graph.trackNodeSourcePosition; + if (sourcePosition == null) { + return; + } + setNodeInfo(NodeSourcePosition.class, sourcePosition); + } + + public void clearNodeSourcePosition() { + setNodeInfo(NodeSourcePosition.class, null); + } + + public NodeCreationStackTrace getCreationPosition() { + return getNodeInfo(NodeCreationStackTrace.class); + } + + public void setCreationPosition(NodeCreationStackTrace trace) { + setNodeInfo(NodeCreationStackTrace.class, trace); + } + + public NodeInsertionStackTrace getInsertionPosition() { + return getNodeInfo(NodeInsertionStackTrace.class); + } + + public void setInsertionPosition(NodeInsertionStackTrace trace) { + setNodeInfo(NodeInsertionStackTrace.class, trace); } /** * Update the source position only if it is null. */ public void updateNodeSourcePosition(Supplier sourcePositionSupp) { - if (this.sourcePosition == null) { + if (this.getNodeSourcePosition() == null) { setNodeSourcePosition(sourcePositionSupp.get()); } } @@ -919,8 +1021,8 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { } newNode.graph = into; newNode.id = INITIAL_ID; - if (sourcePosition != null && (into == null || into.updateNodeSourcePosition())) { - newNode.setNodeSourcePosition(sourcePosition); + if (getNodeSourcePosition() != null && (into == null || into.updateNodeSourcePosition())) { + newNode.setNodeSourcePosition(getNodeSourcePosition()); } if (into != null) { into.register(newNode); @@ -1077,6 +1179,14 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface { if (pos != null) { map.put("nodeSourcePosition", pos); } + NodeCreationStackTrace creation = getCreationPosition(); + if (creation != null) { + map.put("nodeCreationPosition", creation.getStrackTraceString()); + } + NodeInsertionStackTrace insertion = getInsertionPosition(); + if (insertion != null) { + map.put("nodeInsertionPosition", insertion.getStrackTraceString()); + } return map; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java index 516b3bf810a..a18ef7f8bdc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java @@ -42,8 +42,8 @@ import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.FieldIntrospection; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.FieldsScanner; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java index 3061de1602c..f4e2c37847c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java @@ -26,8 +26,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.function.BiFunction; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.MapCursor; public class NodeMap extends NodeIdAccessor implements EconomicMap { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java index 660dc2c7464..b4216b7bbee 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java @@ -64,6 +64,21 @@ public class NodeSourcePosition extends BytecodePosition { return this; } + public ResolvedJavaMethod getRootMethod() { + NodeSourcePosition cur = this; + while (cur.getCaller() != null) { + cur = cur.getCaller(); + } + return cur.getMethod(); + } + + public boolean verifyRootMethod(ResolvedJavaMethod root) { + JavaMethod currentRoot = getRootMethod(); + assert root.equals(currentRoot) || root.getName().equals(currentRoot.getName()) && root.getSignature().toMethodDescriptor().equals(currentRoot.getSignature().toMethodDescriptor()) && + root.getDeclaringClass().getName().equals(currentRoot.getDeclaringClass().getName()) : root + " " + currentRoot; + return true; + } + enum Marker { None, Placeholder, @@ -107,11 +122,11 @@ public class NodeSourcePosition extends BytecodePosition { } public static NodeSourcePosition substitution(ResolvedJavaMethod method) { - return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Substitution); + return substitution(null, method); } - public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { - return new NodeSourcePosition(caller, method, bci, Substitution); + public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method) { + return new NodeSourcePosition(caller, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Substitution); } public boolean isSubstitution() { @@ -151,7 +166,7 @@ public class NodeSourcePosition extends BytecodePosition { return d; } - public SourceLanguagePosition getSourceLanauage() { + public SourceLanguagePosition getSourceLanguage() { return sourceLanguagePosition; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java index cf7f6bb94e8..736aa5143d2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.graph; -import java.util.Map; +import java.net.URI; /** * Provides a path to report information about a high level language source position to the Graph @@ -30,15 +30,23 @@ import java.util.Map; */ public interface SourceLanguagePosition { - /** - * This is called during dumping of Nodes. The implementation should add any properties which - * describe this source position. The actual keys and values used are a private contract between - * the language implementation and the Graph Visualizer. - */ - void addSourceInformation(Map props); - /** * Produce a compact description of this position suitable for printing. */ String toShortString(); + + /** Mimics GraphLocations operation. */ + int getOffsetEnd(); + + /** Mimics GraphLocations operation. */ + int getOffsetStart(); + + /** Mimics GraphLocations operation. */ + int getLineNumber(); + + /** Mimics GraphLocations operation. */ + URI getURI(); + + /** Mimics GraphLocations operation. */ + String getLanguage(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java index 28f3c6db2e8..34844a51feb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java @@ -31,7 +31,7 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.aarch64.AArch64Address; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java index f25ff3d71f8..020459cb798 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java @@ -35,6 +35,7 @@ import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotBackendFactory; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl; +import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider; import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider; @@ -50,7 +51,11 @@ import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import org.graalvm.compiler.nodes.spi.LoweringProvider; +import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.Phase; +import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.aarch64.AArch64GraphBuilderPlugins; @@ -77,7 +82,7 @@ public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory { @Override public String getName() { - return "core"; + return "community"; } @Override @@ -141,7 +146,7 @@ public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory { replacements.setGraphBuilderPlugins(plugins); } try (InitTimer rt = timer("create Suites provider")) { - suites = createSuites(config, graalRuntime, compilerConfiguration, plugins); + suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, replacements); } providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers, snippetReflection, wordTypes, @@ -178,8 +183,11 @@ public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory { return new AArch64HotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); } - protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins) { - return new AArch64HotSpotSuitesProvider(new AArch64SuitesCreator(compilerConfiguration, plugins), config, runtime, new AArch64AddressLoweringByUse(new AArch64LIRKindTool())); + protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, + @SuppressWarnings("unused") Replacements replacements) { + AArch64SuitesCreator suitesCreator = new AArch64SuitesCreator(compilerConfiguration, plugins, SchedulePhase.class); + Phase addressLoweringPhase = new AddressLoweringByUsePhase(new AArch64AddressLoweringByUse(new AArch64LIRKindTool())); + return new AddressLoweringHotSpotSuitesProvider(suitesCreator, config, runtime, addressLoweringPhase); } protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java index aff7f0ee6fb..db3473d812e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java @@ -31,7 +31,7 @@ import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEff import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF; import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; import static org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions.UPDATE_BYTES_CRC32C; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java index f2eb47b145a..3401928839c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotJumpToExceptionHandlerInCallerOp.java @@ -35,6 +35,7 @@ import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -68,11 +69,12 @@ public class AArch64HotSpotJumpToExceptionHandlerInCallerOp extends AArch64HotSp public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { leaveFrame(crb, masm, /* emitSafepoint */false); - if (System.getProperty("java.specification.version").compareTo("1.8") < 0) { + if (GraalServices.JAVA_SPECIFICATION_VERSION < 8) { // Restore sp from fp if the exception PC is a method handle call site. try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); - AArch64Address address = masm.makeAddress(thread, isMethodHandleReturnOffset, scratch, 4, /* allowOverwrite */false); + final boolean allowOverwrite = false; + AArch64Address address = masm.makeAddress(thread, isMethodHandleReturnOffset, scratch, 4, allowOverwrite); masm.ldr(32, scratch, address); Label noRestore = new Label(); masm.cbz(32, scratch, noRestore); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java index d4013c5974e..903b1a4b7ab 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotRegisterAllocationConfig.java @@ -42,7 +42,6 @@ import static jdk.vm.ci.aarch64.AArch64.r23; import static jdk.vm.ci.aarch64.AArch64.r24; import static jdk.vm.ci.aarch64.AArch64.r25; import static jdk.vm.ci.aarch64.AArch64.r26; -import static jdk.vm.ci.aarch64.AArch64.r27; import static jdk.vm.ci.aarch64.AArch64.r28; import static jdk.vm.ci.aarch64.AArch64.r3; import static jdk.vm.ci.aarch64.AArch64.r4; @@ -100,7 +99,7 @@ public class AArch64HotSpotRegisterAllocationConfig extends RegisterAllocationCo r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, - r24, r25, r26, r27, r28, /* r29, r30, r31 */ + r24, r25, r26, /* r27, */ r28, /* r29, r30, r31 */ v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java deleted file mode 100644 index 41ab1423bcf..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSuitesProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, Red Hat Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 org.graalvm.compiler.hotspot.aarch64; - -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase; -import org.graalvm.compiler.phases.common.ExpandLogicPhase; -import org.graalvm.compiler.phases.common.FixReadsPhase; -import org.graalvm.compiler.phases.common.PropagateDeoptimizeProbabilityPhase; -import org.graalvm.compiler.phases.tiers.LowTierContext; -import org.graalvm.compiler.phases.tiers.Suites; -import org.graalvm.compiler.phases.tiers.SuitesCreator; -import org.graalvm.compiler.replacements.aarch64.AArch64ReadReplacementPhase; - -import java.util.ListIterator; - -/** - * Subclass to factor out management of address lowering. - */ -public class AArch64HotSpotSuitesProvider extends HotSpotSuitesProvider { - - private final AddressLoweringByUsePhase.AddressLoweringByUse addressLoweringByUse; - - public AArch64HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, - AddressLoweringByUsePhase.AddressLoweringByUse addressLoweringByUse) { - super(defaultSuitesCreator, config, runtime); - this.addressLoweringByUse = addressLoweringByUse; - } - - @Override - public Suites createSuites(OptionValues options) { - Suites suites = super.createSuites(options); - - ListIterator> findPhase = suites.getLowTier().findPhase(FixReadsPhase.class); - if (findPhase == null) { - findPhase = suites.getLowTier().findPhase(ExpandLogicPhase.class); - } - findPhase.add(new AddressLoweringByUsePhase(addressLoweringByUse)); - - findPhase = suites.getLowTier().findPhase(PropagateDeoptimizeProbabilityPhase.class); - findPhase.add(new AArch64ReadReplacementPhase()); - - return suites; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java index e14ed05b01c..0ba308e7dfb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.hotspot.amd64; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; import org.graalvm.compiler.core.amd64.AMD64AddressNode; import org.graalvm.compiler.core.amd64.AMD64CompressAddressLowering; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 0bab1a412da..aa044076212 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -30,7 +30,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.CanOmitFrame; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.amd64.AMD64Address; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java index 4b570049fac..a39d17b7387 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java @@ -52,6 +52,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plu import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.common.AddressLoweringPhase; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.amd64.AMD64GraphBuilderPlugins; @@ -77,7 +78,7 @@ public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory { @Override public String getName() { - return "core"; + return "community"; } @Override @@ -186,7 +187,7 @@ public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory { protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, HotSpotRegistersProvider registers, Replacements replacements, OptionValues options) { return new AddressLoweringHotSpotSuitesProvider(new AMD64HotSpotSuitesCreator(compilerConfiguration, plugins), config, runtime, - new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister(), options)); + new AddressLoweringPhase(new AMD64HotSpotAddressLowering(config, registers.getHeapBaseRegister(), options))); } protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java index d1caa3b8d0e..cedf17868ea 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java @@ -34,7 +34,7 @@ import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition. import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP; import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; import static org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions.UPDATE_BYTES_CRC32C; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java index 03b9b857949..80089a92eba 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java @@ -33,6 +33,7 @@ import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -68,7 +69,7 @@ final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpi // Discard the return address, thus completing restoration of caller frame masm.incrementq(rsp, 8); - if (System.getProperty("java.specification.version").compareTo("1.8") < 0) { + if (GraalServices.JAVA_SPECIFICATION_VERSION < 8) { // Restore rsp from rbp if the exception PC is a method handle call site. AMD64Address dst = new AMD64Address(thread, isMethodHandleReturnOffset); masm.cmpl(dst, 0); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java index 9c08e127df5..c0d3c823818 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java @@ -46,9 +46,9 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.sparc.SPARCAddress; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java index 4abd8e73857..7a0a8379558 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java @@ -49,6 +49,7 @@ import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.Replacements; +import org.graalvm.compiler.phases.common.AddressLoweringPhase; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; @@ -72,7 +73,7 @@ public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory { @Override public String getName() { - return "core"; + return "community"; } @Override @@ -125,7 +126,7 @@ public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory { */ protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, Replacements replacements) { - return new AddressLoweringHotSpotSuitesProvider(new SPARCSuitesCreator(compilerConfiguration, plugins), config, runtime, new SPARCAddressLowering()); + return new AddressLoweringHotSpotSuitesProvider(new SPARCSuitesCreator(compilerConfiguration, plugins), config, runtime, new AddressLoweringPhase(new SPARCAddressLowering())); } protected SPARCHotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java index a82a1f62912..0285d1caa14 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java @@ -35,7 +35,7 @@ import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEff import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NOFP; import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; import static org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions.UPDATE_BYTES_CRC32C; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java index 93a141924f8..bd68a9021de 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java @@ -32,8 +32,8 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; @@ -43,7 +43,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Binding; import org.graalvm.compiler.runtime.RuntimeProvider; -import org.graalvm.compiler.serviceprovider.JDK9Method; +import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.compiler.test.GraalTest; import org.junit.Test; @@ -542,11 +542,11 @@ public class CheckGraalIntrinsics extends GraalTest { } private static boolean isJDK9OrHigher() { - return JDK9Method.JAVA_SPECIFICATION_VERSION >= 9; + return GraalServices.JAVA_SPECIFICATION_VERSION >= 9; } private static boolean isJDK10OrHigher() { - return JDK9Method.JAVA_SPECIFICATION_VERSION >= 10; + return GraalServices.JAVA_SPECIFICATION_VERSION >= 10; } private static String getHostArchitectureName() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java index dea1d25a430..c990c8a2d7a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java @@ -105,7 +105,6 @@ public class CompilationWrapperTest extends GraalCompilerTest { public void testVMCompilation3() throws IOException, InterruptedException { final int maxProblems = 4; Probe[] probes = { - new Probe("To capture more information for diagnosing or reporting a compilation", maxProblems), new Probe("Retrying compilation of", maxProblems) { @Override String test() { @@ -131,6 +130,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { testHelper(Collections.emptyList(), Arrays.asList( "-Dgraal.CompilationFailureAction=ExitVM", + "-Dgraal.TrufflePerformanceWarningsAreFatal=true", "-Dgraal.CrashAt=root test1"), "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); } @@ -151,6 +151,22 @@ public class CompilationWrapperTest extends GraalCompilerTest { "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); } + /** + * Tests that TrufflePerformanceWarningsAreFatal generates diagnostic output. + */ + @Test + public void testTruffleCompilation3() throws IOException, InterruptedException { + Probe[] probes = { + new Probe("Exiting VM due to TrufflePerformanceWarningsAreFatal=true", 1), + }; + testHelper(Arrays.asList(probes), + Arrays.asList( + "-Dgraal.CompilationFailureAction=Silent", + "-Dgraal.TrufflePerformanceWarningsAreFatal=true", + "-Dgraal.CrashAt=root test1:PermanentBailout"), + "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); + } + private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose"); private static void testHelper(List initialProbes, List extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException { @@ -225,7 +241,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc)); } if (cfg == 0) { - Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries)); + Assert.fail(String.format("Expected at least one .cfg file in %s: %s%n%s", diagnosticOutputZip, entries, proc)); } } finally { zip.delete(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java index 146296fe83d..ac4dc3564ff 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java @@ -29,7 +29,7 @@ import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureA import static org.graalvm.compiler.core.test.ReflectionOptionDescriptors.extractEntries; import static org.graalvm.compiler.debug.MemUseTrackerKey.getCurrentThreadAllocatedBytes; import static org.graalvm.compiler.hotspot.test.CompileTheWorld.Options.DESCRIPTORS; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import java.io.Closeable; import java.io.File; @@ -66,10 +66,12 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.bytecode.Bytecodes; import org.graalvm.compiler.core.CompilerThreadFactory; @@ -86,7 +88,7 @@ import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.options.OptionsParser; -import org.graalvm.compiler.serviceprovider.JDK9Method; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.hotspot.HotSpotCompilationRequest; @@ -107,8 +109,8 @@ public final class CompileTheWorld { /** * Magic token to denote that JDK classes are to be compiled. If - * {@link JDK9Method#Java8OrEarlier}, then the classes in {@code rt.jar} are compiled. Otherwise - * the classes in the Java runtime image are compiled. + * {@link GraalServices#Java8OrEarlier}, then the classes in {@code rt.jar} are compiled. + * Otherwise the classes in the Java runtime image are compiled. */ public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; @@ -379,6 +381,11 @@ public final class CompileTheWorld { return new URLClassLoader(new URL[]{url}); } + /** + * @see "https://docs.oracle.com/javase/9/docs/specs/jar/jar.html#Multi-release" + */ + static Pattern MultiReleaseJarVersionedClassRE = Pattern.compile("META-INF/versions/[1-9][0-9]*/(.+)"); + @Override public List getClassNames() throws IOException { Enumeration e = jarFile.entries(); @@ -389,6 +396,17 @@ public final class CompileTheWorld { continue; } String className = je.getName().substring(0, je.getName().length() - ".class".length()); + if (className.equals("module-info")) { + continue; + } + if (className.startsWith("META-INF/versions/")) { + Matcher m = MultiReleaseJarVersionedClassRE.matcher(className); + if (m.matches()) { + className = m.group(1); + } else { + continue; + } + } classNames.add(className.replace('/', '.')); } return classNames; @@ -562,6 +580,10 @@ public final class CompileTheWorld { continue; } + if (!isClassIncluded(className)) { + continue; + } + try { // Load and initialize class Class javaClass = Class.forName(className, true, loader); @@ -581,14 +603,6 @@ public final class CompileTheWorld { continue; } - /* - * Only check filters after class loading and resolution to mitigate impact - * on reproducibility. - */ - if (!isClassIncluded(className)) { - continue; - } - // Are we compiling this class? MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); if (classFileCounter >= startAt) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java index e151de4832b..f26a1e53e54 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.hotspot.test; import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationBailoutAction; import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureAction; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java index d3c5286301d..165695ff550 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.hotspot.test; import java.lang.management.ManagementFactory; import java.lang.management.MonitorInfo; -import java.lang.management.RuntimeMXBean; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.Collection; @@ -32,7 +31,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.phases.HighTier; import org.graalvm.compiler.debug.DebugContext; @@ -41,6 +40,7 @@ import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; import org.junit.Assert; import org.junit.Assume; import org.junit.BeforeClass; @@ -58,11 +58,6 @@ public class GraalOSRLockTest extends GraalOSRTestBase { @BeforeClass public static void checkVMArguments() { - try { - Class.forName("java.lang.management.ManagementFactory"); - } catch (ClassNotFoundException ex) { - Assume.assumeNoException("cannot check for monitors without java.management JDK9 module", ex); - } /* * Note: The -Xcomp execution mode of the VM will stop most of the OSR test cases from * working as every method is compiled at level3 (followed by level4 on the second @@ -71,8 +66,8 @@ public class GraalOSRLockTest extends GraalOSRTestBase { * installed nmethod at a given BCI. * */ - RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); - List arguments = runtimeMxBean.getInputArguments(); + List arguments = GraalServices.getInputArguments(); + Assume.assumeTrue("cannot check for monitors without", arguments != null); for (String arg : arguments) { Assume.assumeFalse(arg.equals(COMPILE_ONLY_FLAG)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java index a978dbf4bac..80dc1f836e1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTest.java @@ -26,6 +26,9 @@ import org.graalvm.compiler.api.directives.GraalDirectives; import org.junit.Assert; import org.junit.Test; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; + /** * Test on-stack-replacement with Graal. The test manually triggers a Graal OSR-compilation which is * later invoked when hitting the backedge counter overflow. @@ -99,4 +102,57 @@ public class GraalOSRTest extends GraalOSRTestBase { return ret; } + @Test + public void testOSR04() { + testFunnyOSR("testDoWhile", GraalOSRTest::testDoWhile); + } + + @Test + public void testOSR05() { + testFunnyOSR("testDoWhileLocked", GraalOSRTest::testDoWhileLocked); + } + + /** + * Because of a bug in C1 profile collection HotSpot can sometimes request an OSR compilation + * for a backedge which isn't ever taken. This test synthetically creates that situation. + */ + private void testFunnyOSR(String name, Runnable warmup) { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + int iterations = 0; + while (true) { + ProfilingInfo profilingInfo = method.getProfilingInfo(); + if (profilingInfo.isMature()) { + break; + } + + warmup.run(); + if (iterations++ % 1000 == 0) { + System.err.print('.'); + } + if (iterations > 200000) { + throw new AssertionError("no profile"); + } + } + compileOSR(getInitialOptions(), method); + Result result = executeExpected(method, null); + checkResult(result); + } + + private static boolean repeatLoop; + + public static ReturnValue testDoWhile() { + do { + sideEffect++; + } while (repeatLoop); + return ReturnValue.SUCCESS; + } + + public static synchronized ReturnValue testDoWhileLocked() { + // synchronized (GraalOSRTest.class) { + do { + sideEffect++; + } while (repeatLoop); + // } + return ReturnValue.SUCCESS; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java index d73449cd9dd..9fda88c3796 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java @@ -29,6 +29,8 @@ import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeDisassembler; import org.graalvm.compiler.bytecode.BytecodeStream; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; +import org.graalvm.compiler.core.GraalCompilerOptions; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; @@ -95,18 +97,18 @@ public abstract class GraalOSRTestBase extends GraalCompilerTest { * Returns the target BCI of the first bytecode backedge. This is where HotSpot triggers * on-stack-replacement in case the backedge counter overflows. */ - private static int getBackedgeBCI(DebugContext debug, ResolvedJavaMethod method) { + static int getBackedgeBCI(DebugContext debug, ResolvedJavaMethod method) { Bytecode code = new ResolvedJavaMethodBytecode(method); BytecodeStream stream = new BytecodeStream(code.getCode()); OptionValues options = debug.getOptions(); BciBlockMapping bciBlockMapping = BciBlockMapping.create(stream, code, options, debug); for (BciBlock block : bciBlockMapping.getBlocks()) { - if (block.startBci != -1) { - int bci = block.startBci; + if (block.getStartBci() != -1) { + int bci = block.getEndBci(); for (BciBlock succ : block.getSuccessors()) { - if (succ.startBci != -1) { - int succBci = succ.startBci; + if (succ.getStartBci() != -1) { + int succBci = succ.getStartBci(); if (succBci < bci) { // back edge return succBci; @@ -120,16 +122,22 @@ public abstract class GraalOSRTestBase extends GraalCompilerTest { return -1; } - private static void checkResult(Result result) { + protected static void checkResult(Result result) { Assert.assertNull("Unexpected exception", result.exception); Assert.assertNotNull(result.returnValue); Assert.assertTrue(result.returnValue instanceof ReturnValue); Assert.assertEquals(ReturnValue.SUCCESS, result.returnValue); } - private void compileOSR(OptionValues options, ResolvedJavaMethod method) { + protected void compileOSR(OptionValues options, ResolvedJavaMethod method) { + OptionValues goptions = options; + // Silence diagnostics for permanent bailout errors as they + // are expected for some OSR tests. + if (!GraalCompilerOptions.CompilationBailoutAction.hasBeenSet(options)) { + goptions = new OptionValues(options, GraalCompilerOptions.CompilationBailoutAction, ExceptionAction.Silent); + } // ensure eager resolving - StructuredGraph graph = parseEager(method, AllowAssumptions.YES, options); + StructuredGraph graph = parseEager(method, AllowAssumptions.YES, goptions); DebugContext debug = graph.getDebug(); int bci = getBackedgeBCI(debug, method); assert bci != -1; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java deleted file mode 100644 index 7ab30fd6dbd..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 org.graalvm.compiler.hotspot.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.lang.management.ManagementFactory; -import java.lang.reflect.Field; -import java.util.Arrays; - -import javax.management.Attribute; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanServer; -import javax.management.ObjectInstance; -import javax.management.ObjectName; - -import org.graalvm.collections.EconomicMap; -import org.graalvm.compiler.debug.DebugOptions; -import org.graalvm.compiler.hotspot.HotSpotGraalMBean; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.test.GraalTest; -import org.junit.Assume; -import org.junit.Test; - -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class HotSpotGraalMBeanTest { - - public HotSpotGraalMBeanTest() { - // No support for registering Graal MBean yet on JDK9 (GR-4025). We cannot - // rely on an exception being thrown when accessing ManagementFactory.platformMBeanServer - // via reflection as recent JDK9 changes now allow this and issue a warning instead. - Assume.assumeTrue(GraalTest.Java8OrEarlier); - } - - @Test - public void registration() throws Exception { - ObjectName name; - - Field field = null; - try { - field = stopMBeanServer(); - } catch (Exception ex) { - if (ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { - // skip on JDK9 - return; - } - } - assertNull("The platformMBeanServer isn't initialized now", field.get(null)); - - HotSpotGraalMBean bean = HotSpotGraalMBean.create(null); - assertNotNull("Bean created", bean); - - assertNull("It is not registered yet", bean.ensureRegistered(true)); - - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - - assertNotNull("Now the bean thinks it is registered", name = bean.ensureRegistered(true)); - - assertNotNull("And the bean is found", server.getObjectInstance(name)); - } - - private static Field stopMBeanServer() throws NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException { - final Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer"); - field.setAccessible(true); - field.set(null, null); - return field; - } - - @Test - public void readBeanInfo() throws Exception { - ObjectName name; - - assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer()); - - HotSpotGraalMBean realBean = HotSpotGraalMBean.create(null); - assertNotNull("Bean is registered", name = realBean.ensureRegistered(false)); - final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - - ObjectInstance bean = server.getObjectInstance(name); - assertNotNull("Bean is registered", bean); - MBeanInfo info = server.getMBeanInfo(name); - assertNotNull("Info is found", info); - - MBeanAttributeInfo printCompilation = (MBeanAttributeInfo) findAttributeInfo("PrintCompilation", info); - assertNotNull("PrintCompilation found", printCompilation); - assertEquals("true/false", Boolean.class.getName(), printCompilation.getType()); - - Attribute printOn = new Attribute(printCompilation.getName(), Boolean.TRUE); - - Object before = server.getAttribute(name, printCompilation.getName()); - server.setAttribute(name, printOn); - Object after = server.getAttribute(name, printCompilation.getName()); - - assertNull("Default value was not set", before); - assertEquals("Changed to on", Boolean.TRUE, after); - } - - private static Object findAttributeInfo(String attrName, Object info) { - MBeanAttributeInfo printCompilation = null; - for (MBeanAttributeInfo attr : ((MBeanInfo) info).getAttributes()) { - if (attr.getName().equals(attrName)) { - assertTrue("Readable", attr.isReadable()); - assertTrue("Writable", attr.isWritable()); - printCompilation = attr; - break; - } - } - return printCompilation; - } - - @Test - public void optionsAreCached() throws Exception { - ObjectName name; - - assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer()); - - HotSpotGraalMBean realBean = HotSpotGraalMBean.create(null); - - OptionValues original = new OptionValues(EconomicMap.create()); - - assertSame(original, realBean.optionsFor(original, null)); - - assertNotNull("Bean is registered", name = realBean.ensureRegistered(false)); - final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - - ObjectInstance bean = server.getObjectInstance(name); - assertNotNull("Bean is registered", bean); - MBeanInfo info = server.getMBeanInfo(name); - assertNotNull("Info is found", info); - - MBeanAttributeInfo dump = (MBeanAttributeInfo) findAttributeInfo("Dump", info); - - Attribute dumpTo1 = new Attribute(dump.getName(), 1); - - server.setAttribute(name, dumpTo1); - Object after = server.getAttribute(name, dump.getName()); - assertEquals(1, after); - - final OptionValues modified1 = realBean.optionsFor(original, null); - assertNotSame(original, modified1); - final OptionValues modified2 = realBean.optionsFor(original, null); - assertSame("Options are cached", modified1, modified2); - - } - - @Test - public void dumpOperation() throws Exception { - Field field = null; - try { - field = stopMBeanServer(); - } catch (Exception ex) { - if (ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { - // skip on JDK9 - return; - } - } - assertNull("The platformMBeanServer isn't initialized now", field.get(null)); - - ObjectName name; - - assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer()); - - HotSpotGraalMBean realBean = HotSpotGraalMBean.create(null); - - assertNotNull("Bean is registered", name = realBean.ensureRegistered(false)); - final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - - ObjectInstance bean = server.getObjectInstance(name); - assertNotNull("Bean is registered", bean); - - MBeanInfo info = server.getMBeanInfo(name); - assertNotNull("Info is found", info); - - final MBeanOperationInfo[] arr = info.getOperations(); - assertEquals("Currently three overloads", 3, arr.length); - MBeanOperationInfo dumpOp = null; - for (int i = 0; i < arr.length; i++) { - assertEquals("dumpMethod", arr[i].getName()); - if (arr[i].getSignature().length == 3) { - dumpOp = arr[i]; - } - } - assertNotNull("three args variant found", dumpOp); - - server.invoke(name, "dumpMethod", new Object[]{ - "java.util.Arrays", "asList", ":3" - }, null); - - MBeanAttributeInfo dump = (MBeanAttributeInfo) findAttributeInfo("Dump", info); - Attribute dumpTo1 = new Attribute(dump.getName(), ""); - server.setAttribute(name, dumpTo1); - Object after = server.getAttribute(name, dump.getName()); - assertEquals("", after); - - OptionValues empty = new OptionValues(EconomicMap.create()); - OptionValues unsetDump = realBean.optionsFor(empty, null); - final MetaAccessProvider metaAccess = jdk.vm.ci.runtime.JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); - ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Arrays.class.getMethod("asList", Object[].class)); - final OptionValues forMethod = realBean.optionsFor(unsetDump, method); - assertNotSame(unsetDump, forMethod); - Object nothing = unsetDump.getMap().get(DebugOptions.Dump); - assertEquals("Empty string", "", nothing); - - Object specialValue = forMethod.getMap().get(DebugOptions.Dump); - assertEquals(":3", specialValue); - - OptionValues normalMethod = realBean.optionsFor(unsetDump, null); - Object noSpecialValue = normalMethod.getMap().get(DebugOptions.Dump); - assertEquals("Empty string", "", noSpecialValue); - } - -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java new file mode 100644 index 00000000000..9907244dc3e --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 org.graalvm.compiler.hotspot.test; + +import static org.graalvm.compiler.hotspot.test.HotSpotGraalManagementTest.JunitShield.findAttributeInfo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.hotspot.HotSpotGraalManagementRegistration; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntime; +import org.graalvm.compiler.options.EnumOptionKey; +import org.graalvm.compiler.options.NestedBooleanOptionKey; +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionsParser; +import org.junit.Assert; +import org.junit.AssumptionViolatedException; +import org.junit.Test; + +public class HotSpotGraalManagementTest { + + private static final boolean DEBUG = Boolean.getBoolean(HotSpotGraalManagementTest.class.getSimpleName() + ".debug"); + + public HotSpotGraalManagementTest() { + try { + MBeanServerFactory.findMBeanServer(null); + } catch (NoClassDefFoundError e) { + throw new AssumptionViolatedException("Management classes/module(s) not available: " + e); + } + } + + @Test + public void registration() throws Exception { + HotSpotGraalRuntime runtime = (HotSpotGraalRuntime) Graal.getRuntime(); + HotSpotGraalManagementRegistration management = runtime.getManagement(); + if (management == null) { + return; + } + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + + ObjectName name; + assertNotNull("Now the bean thinks it is registered", name = (ObjectName) management.poll(true)); + + assertNotNull("And the bean is found", server.getObjectInstance(name)); + } + + @Test + public void readBeanInfo() throws Exception { + + assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer()); + + HotSpotGraalRuntime runtime = (HotSpotGraalRuntime) Graal.getRuntime(); + HotSpotGraalManagementRegistration management = runtime.getManagement(); + if (management == null) { + return; + } + + ObjectName mbeanName; + assertNotNull("Bean is registered", mbeanName = (ObjectName) management.poll(true)); + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + + ObjectInstance bean = server.getObjectInstance(mbeanName); + assertNotNull("Bean is registered", bean); + MBeanInfo info = server.getMBeanInfo(mbeanName); + assertNotNull("Info is found", info); + + AttributeList originalValues = new AttributeList(); + AttributeList newValues = new AttributeList(); + for (OptionDescriptors set : OptionsParser.getOptionsLoader()) { + for (OptionDescriptor option : set) { + JunitShield.testOption(info, mbeanName, server, runtime, option, newValues, originalValues); + } + } + + String[] attributeNames = new String[originalValues.size()]; + for (int i = 0; i < attributeNames.length; i++) { + attributeNames[i] = ((Attribute) originalValues.get(i)).getName(); + } + AttributeList actualValues = server.getAttributes(mbeanName, attributeNames); + assertEquals(originalValues.size(), actualValues.size()); + for (int i = 0; i < attributeNames.length; i++) { + Object expect = String.valueOf(((Attribute) originalValues.get(i)).getValue()); + Object actual = String.valueOf(((Attribute) actualValues.get(i)).getValue()); + assertEquals(attributeNames[i], expect, actual); + } + + try { + server.setAttributes(mbeanName, newValues); + } finally { + server.setAttributes(mbeanName, originalValues); + } + } + + /** + * Junit scans all methods of a test class and tries to resolve all method parameter and return + * types. We hide such methods in an inner class to prevent errors such as: + * + *
+     * java.lang.NoClassDefFoundError: javax/management/MBeanInfo
+     *     at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
+     *     at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3119)
+     *     at java.base/java.lang.Class.getDeclaredMethods(Class.java:2268)
+     *     at org.junit.internal.MethodSorter.getDeclaredMethods(MethodSorter.java:54)
+     *     at org.junit.runners.model.TestClass.scanAnnotatedMembers(TestClass.java:65)
+     *     at org.junit.runners.model.TestClass.(TestClass.java:57)
+     *
+     * 
+ */ + static class JunitShield { + + /** + * Tests changing the value of {@code option} via the management interface to a) a new legal + * value and b) an illegal value. + */ + static void testOption(MBeanInfo mbeanInfo, + ObjectName mbeanName, + MBeanServer server, + HotSpotGraalRuntime runtime, + OptionDescriptor option, + AttributeList newValues, + AttributeList originalValues) throws Exception { + OptionKey optionKey = option.getOptionKey(); + Object currentValue = optionKey.getValue(runtime.getOptions()); + Class optionType = option.getOptionValueType(); + String name = option.getName(); + if (DEBUG) { + System.out.println("Testing option " + name); + } + MBeanAttributeInfo attrInfo = findAttributeInfo(name, mbeanInfo); + assertNotNull("Attribute not found for option " + name, attrInfo); + + String expectAttributeValue = stringValue(currentValue, option.getOptionValueType() == String.class); + Object actualAttributeValue = server.getAttribute(mbeanName, name); + assertEquals(expectAttributeValue, actualAttributeValue); + + Map legalValues = new HashMap<>(); + List illegalValues = new ArrayList<>(); + if (optionKey instanceof EnumOptionKey) { + EnumOptionKey enumOptionKey = (EnumOptionKey) optionKey; + for (Object obj : enumOptionKey.getAllValues()) { + if (obj != currentValue) { + legalValues.put(obj.toString(), obj.toString()); + } + } + illegalValues.add(String.valueOf(42)); + } else if (optionType == Boolean.class) { + Object defaultValue; + if (optionKey instanceof NestedBooleanOptionKey) { + NestedBooleanOptionKey nbok = (NestedBooleanOptionKey) optionKey; + defaultValue = nbok.getMasterOption().getValue(runtime.getOptions()); + } else { + defaultValue = optionKey.getDefaultValue(); + } + legalValues.put("", unquotedStringValue(defaultValue)); + illegalValues.add(String.valueOf(42)); + illegalValues.add("true"); + illegalValues.add("false"); + } else if (optionType == String.class) { + legalValues.put("", quotedStringValue(optionKey.getDefaultValue())); + legalValues.put("\"" + currentValue + "Prime\"", "\"" + currentValue + "Prime\""); + legalValues.put("\"quoted string\"", "\"quoted string\""); + illegalValues.add("\"unbalanced quotes"); + illegalValues.add("\""); + illegalValues.add("non quoted string"); + } else if (optionType == Float.class) { + legalValues.put("", unquotedStringValue(optionKey.getDefaultValue())); + String value = unquotedStringValue(currentValue == null ? 33F : ((float) currentValue) + 11F); + legalValues.put(value, value); + illegalValues.add("string"); + } else if (optionType == Double.class) { + legalValues.put("", unquotedStringValue(optionKey.getDefaultValue())); + String value = unquotedStringValue(currentValue == null ? 33D : ((double) currentValue) + 11D); + legalValues.put(value, value); + illegalValues.add("string"); + } else if (optionType == Integer.class) { + legalValues.put("", unquotedStringValue(optionKey.getDefaultValue())); + String value = unquotedStringValue(currentValue == null ? 33 : ((int) currentValue) + 11); + legalValues.put(value, value); + illegalValues.add("42.42"); + illegalValues.add("string"); + } else if (optionType == Long.class) { + legalValues.put("", unquotedStringValue(optionKey.getDefaultValue())); + String value = unquotedStringValue(currentValue == null ? 33L : ((long) currentValue) + 11L); + legalValues.put(value, value); + illegalValues.add("42.42"); + illegalValues.add("string"); + } + + Attribute originalAttributeValue = new Attribute(name, expectAttributeValue); + try { + for (Map.Entry e : legalValues.entrySet()) { + String legalValue = e.getKey(); + if (DEBUG) { + System.out.printf("Changing %s from %s to %s%n", name, currentValue, legalValue); + } + Attribute newAttributeValue = new Attribute(name, legalValue); + newValues.add(newAttributeValue); + server.setAttribute(mbeanName, newAttributeValue); + Object actual = optionKey.getValue(runtime.getOptions()); + actual = server.getAttribute(mbeanName, name); + String expectValue = e.getValue(); + if (option.getOptionValueType() == String.class && expectValue == null) { + expectValue = ""; + } else if (option.getOptionKey() instanceof NestedBooleanOptionKey && null == expectValue) { + NestedBooleanOptionKey nbok = (NestedBooleanOptionKey) option.getOptionKey(); + expectValue = String.valueOf(nbok.getValue(runtime.getOptions())); + actual = server.getAttribute(mbeanName, name); + } + assertEquals(expectValue, actual); + } + } finally { + if (DEBUG) { + System.out.printf("Resetting %s to %s%n", name, currentValue); + } + originalValues.add(originalAttributeValue); + server.setAttribute(mbeanName, originalAttributeValue); + } + + try { + for (Object illegalValue : illegalValues) { + if (DEBUG) { + System.out.printf("Changing %s from %s to illegal value %s%n", name, currentValue, illegalValue); + } + server.setAttribute(mbeanName, new Attribute(name, illegalValue)); + Assert.fail("Expected setting " + name + " to " + illegalValue + " to fail"); + } + } catch (InvalidAttributeValueException e) { + // Expected + } finally { + if (DEBUG) { + System.out.printf("Resetting %s to %s%n", name, currentValue); + } + server.setAttribute(mbeanName, originalAttributeValue); + } + + try { + + String unknownOptionName = "definitely not an option name"; + server.setAttribute(mbeanName, new Attribute(unknownOptionName, "")); + Assert.fail("Expected setting option with name \"" + unknownOptionName + "\" to fail"); + } catch (AttributeNotFoundException e) { + // Expected + } + } + + static MBeanAttributeInfo findAttributeInfo(String attrName, MBeanInfo info) { + for (MBeanAttributeInfo attr : info.getAttributes()) { + if (attr.getName().equals(attrName)) { + assertTrue("Readable", attr.isReadable()); + assertTrue("Writable", attr.isWritable()); + return attr; + } + } + return null; + } + } + + private static String quotedStringValue(Object optionValue) { + return stringValue(optionValue, true); + } + + private static String unquotedStringValue(Object optionValue) { + return stringValue(optionValue, false); + } + + private static String stringValue(Object optionValue, boolean withQuoting) { + if (optionValue == null) { + return ""; + } + if (withQuoting) { + return "\"" + optionValue + "\""; + } + return String.valueOf(optionValue); + } + + private static String quoted(Object s) { + return "\"" + s + "\""; + } + + /** + * Tests publicaly visible names and identifiers used by tools developed and distributed on an + * independent schedule (like VisualVM). Consider keeping the test passing without any semantic + * modifications. The cost of changes is higher than you estimate. Include all available + * stakeholders as reviewers to give them a chance to stop you before causing too much damage. + */ + @Test + public void publicJmxApiOfGraalDumpOperation() throws Exception { + assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer()); + + HotSpotGraalRuntime runtime = (HotSpotGraalRuntime) Graal.getRuntime(); + HotSpotGraalManagementRegistration management = runtime.getManagement(); + if (management == null) { + return; + } + + ObjectName mbeanName; + assertNotNull("Bean is registered", mbeanName = (ObjectName) management.poll(true)); + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + + assertEquals("Domain name is used to lookup the beans by VisualVM", "org.graalvm.compiler.hotspot", mbeanName.getDomain()); + assertEquals("type can be used to identify the Graal bean", "HotSpotGraalRuntime_VM", mbeanName.getKeyProperty("type")); + + ObjectInstance bean = server.getObjectInstance(mbeanName); + assertNotNull("Bean is registered", bean); + + MBeanInfo info = server.getMBeanInfo(mbeanName); + assertNotNull("Info is found", info); + + final MBeanOperationInfo[] arr = info.getOperations(); + assertEquals("Currently three overloads", 3, arr.length); + MBeanOperationInfo dumpOp = null; + for (int i = 0; i < arr.length; i++) { + assertEquals("dumpMethod", arr[i].getName()); + if (arr[i].getSignature().length == 3) { + dumpOp = arr[i]; + } + } + assertNotNull("three args variant (as used by VisualVM) found", dumpOp); + + MBeanAttributeInfo dumpPath = findAttributeInfo("DumpPath", info); + MBeanAttributeInfo printGraphFile = findAttributeInfo("PrintGraphFile", info); + MBeanAttributeInfo showDumpFiles = findAttributeInfo("ShowDumpFiles", info); + Object originalDumpPath = server.getAttribute(mbeanName, dumpPath.getName()); + Object originalPrintGraphFile = server.getAttribute(mbeanName, printGraphFile.getName()); + Object originalShowDumpFiles = server.getAttribute(mbeanName, showDumpFiles.getName()); + final File tmpDir = new File(HotSpotGraalManagementTest.class.getSimpleName() + "_" + System.currentTimeMillis()).getAbsoluteFile(); + + server.setAttribute(mbeanName, new Attribute(dumpPath.getName(), quoted(tmpDir))); + // Force output to a file even if there's a running IGV instance available. + server.setAttribute(mbeanName, new Attribute(printGraphFile.getName(), true)); + server.setAttribute(mbeanName, new Attribute(showDumpFiles.getName(), false)); + Object[] params = {"java.util.Arrays", "asList", ":3"}; + try { + server.invoke(mbeanName, "dumpMethod", params, null); + boolean found = false; + String expectedIgvDumpSuffix = "[Arrays.asList(Object[])List].bgv"; + List dumpPathEntries = Arrays.asList(tmpDir.list()); + for (String entry : dumpPathEntries) { + if (entry.endsWith(expectedIgvDumpSuffix)) { + found = true; + } + } + if (!found) { + Assert.fail(String.format("Expected file ending with \"%s\" in %s but only found:%n%s", expectedIgvDumpSuffix, tmpDir, + dumpPathEntries.stream().collect(Collectors.joining(System.lineSeparator())))); + } + } finally { + deleteDirectory(tmpDir.toPath()); + server.setAttribute(mbeanName, new Attribute(dumpPath.getName(), originalDumpPath)); + server.setAttribute(mbeanName, new Attribute(printGraphFile.getName(), originalPrintGraphFile)); + server.setAttribute(mbeanName, new Attribute(showDumpFiles.getName(), originalShowDumpFiles)); + } + } + + static void deleteDirectory(Path toDelete) throws IOException { + Files.walk(toDelete).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java index a93e0d9399d..cd22a1f145b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java @@ -46,6 +46,17 @@ public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest { test("getClass0", "a string"); test("objectHashCode", obj); + + testGraph("objectNotify", "Object.notify"); + testGraph("objectNotifyAll", "Object.notifyAll"); + + synchronized (obj) { + test("objectNotify", obj); + test("objectNotifyAll", obj); + } + // Test with IllegalMonitorStateException (no synchronized block) + test("objectNotify", obj); + test("objectNotifyAll", obj); } @SuppressWarnings("all") @@ -58,6 +69,16 @@ public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest { return obj.hashCode(); } + @SuppressWarnings("all") + public static void objectNotify(Object obj) { + obj.notify(); + } + + @SuppressWarnings("all") + public static void objectNotifyAll(Object obj) { + obj.notifyAll(); + } + @Test public void testClassSubstitutions() { testGraph("getModifiers"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStampMemoryAccessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStampMemoryAccessTest.java index 74bfeaa3b9e..27c844f2832 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStampMemoryAccessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStampMemoryAccessTest.java @@ -28,7 +28,6 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp; import org.junit.Assume; -import org.junit.Ignore; import org.junit.Test; import jdk.vm.ci.meta.JavaConstant; @@ -37,7 +36,6 @@ import jdk.vm.ci.meta.MemoryAccessProvider; public class HotSpotStampMemoryAccessTest extends HotSpotGraalCompilerTest { - @Ignore("not all versions are safe yet") @Test public void testReadNarrowObject() { CompressEncoding oopEncoding = runtime().getVMConfig().getOopEncoding(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java index 6ed19c8bbe9..2f20f916ba9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java @@ -26,7 +26,7 @@ import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COM import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java index a146a30596d..018133cb6a1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.hotspot.test; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Scope; @@ -59,7 +59,7 @@ import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.MidTierContext; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa new file mode 100644 index 00000000000..9b123f4703b --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.test; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class HotSpotLazyInitializationTest extends GraalCompilerTest { + + HotSpotClassInitializationPlugin classInitPlugin = new HotSpotClassInitializationPlugin(); + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + plugins.setClassInitializationPlugin(classInitPlugin); + return plugins; + } + + static boolean X_initialized = false; + + static class X { + static { + X_initialized = true; + } + static void foo() {} + } + + public static void invokeStatic() { + X.foo(); + } + + private void test(String name) { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool())); + StructuredGraph graph = parseEager(method, AllowAssumptions.NO); + Assert.assertFalse(X_initialized); + } + + @Test + public void test1() { + test("invokeStatic"); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CommunityCompilerConfigurationFactory.java similarity index 70% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CommunityCompilerConfigurationFactory.java index 2dec9453772..d085e7b63a8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CoreCompilerConfigurationFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CommunityCompilerConfigurationFactory.java @@ -22,23 +22,30 @@ */ package org.graalvm.compiler.hotspot; -import org.graalvm.compiler.core.phases.CoreCompilerConfiguration; +import org.graalvm.compiler.core.phases.CommunityCompilerConfiguration; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.serviceprovider.ServiceProvider; +/** + * Factory for creating the default configuration for the community edition of Graal. + */ @ServiceProvider(CompilerConfigurationFactory.class) -public class CoreCompilerConfigurationFactory extends CompilerConfigurationFactory { +public class CommunityCompilerConfigurationFactory extends CompilerConfigurationFactory { - public static final String NAME = "core"; + public static final String NAME = "community"; + /** + * Must be greater than {@link EconomyCompilerConfigurationFactory#AUTO_SELECTION_PRIORITY}. + */ public static final int AUTO_SELECTION_PRIORITY = 2; - public CoreCompilerConfigurationFactory() { + public CommunityCompilerConfigurationFactory() { super(NAME, AUTO_SELECTION_PRIORITY); + assert AUTO_SELECTION_PRIORITY > EconomyCompilerConfigurationFactory.AUTO_SELECTION_PRIORITY; } @Override public CompilerConfiguration createCompilerConfiguration() { - return new CoreCompilerConfiguration(); + return new CommunityCompilerConfiguration(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java index ab4fdb18be8..9b194513409 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java @@ -42,10 +42,10 @@ import java.util.Locale; import java.util.concurrent.ConcurrentLinkedDeque; import org.graalvm.compiler.debug.CSVUtil; -import org.graalvm.compiler.debug.Management; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.hotspot.HotSpotInstalledCode; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -87,8 +87,7 @@ public final class CompilationStatistics { private static long zeroTime = System.nanoTime(); private static long getThreadAllocatedBytes() { - com.sun.management.ThreadMXBean thread = (com.sun.management.ThreadMXBean) Management.getThreadMXBean(); - return thread.getThreadAllocatedBytes(currentThread().getId()); + return GraalServices.getCurrentThreadAllocatedBytes(); } @NotReported private final long startTime; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java index 10f744d46a4..a3c8118df0c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java @@ -22,14 +22,16 @@ */ package org.graalvm.compiler.hotspot; +import static org.graalvm.compiler.core.CompilationWrapper.ExceptionAction.Diagnose; import static org.graalvm.compiler.core.CompilationWrapper.ExceptionAction.ExitVM; +import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationBailoutAction; import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureAction; import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.CompilationPrinter; @@ -140,17 +142,25 @@ public class CompilationTask { } @Override - protected ExceptionAction lookupAction(OptionValues values, EnumOptionKey actionKey) { - /* - * Automatically exit VM on non-bailout during bootstrap or when asserts are enabled but - * respect CompilationFailureAction if it has been explicitly set. - */ - if (actionKey == CompilationFailureAction && !actionKey.hasBeenSet(values)) { - if (Assertions.assertionsEnabled() || compiler.getGraalRuntime().isBootstrapping()) { - return ExitVM; + protected ExceptionAction lookupAction(OptionValues values, EnumOptionKey actionKey, Throwable cause) { + // Respect current action if it has been explicitly set. + if (!actionKey.hasBeenSet(values)) { + if (actionKey == CompilationFailureAction) { + // Automatically exit on non-bailout during bootstrap + // or when assertions are enabled. + if (Assertions.assertionsEnabled() || compiler.getGraalRuntime().isBootstrapping()) { + return ExitVM; + } + } else if (actionKey == CompilationBailoutAction && ((BailoutException) cause).isPermanent()) { + // Get more info for permanent bailouts during bootstrap + // or when assertions are enabled. + assert CompilationBailoutAction.getDefaultValue() == ExceptionAction.Silent; + if (Assertions.assertionsEnabled() || compiler.getGraalRuntime().isBootstrapping()) { + return Diagnose; + } } } - return super.lookupAction(values, actionKey); + return super.lookupAction(values, actionKey, cause); } @SuppressWarnings("try") @@ -187,6 +197,7 @@ public class CompilationTask { } return null; } + } public CompilationTask(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean installAsDefault, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java index 18d6cb873f2..f70d20d4bd2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java @@ -31,7 +31,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.lir.phases.LIRPhase; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java index c9e4c087c90..ac0b4524637 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EconomyCompilerConfigurationFactory.java @@ -26,6 +26,9 @@ import org.graalvm.compiler.core.phases.EconomyCompilerConfiguration; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.serviceprovider.ServiceProvider; +/** + * Factory that creates a {@link EconomyCompilerConfiguration}. + */ @ServiceProvider(CompilerConfigurationFactory.class) public class EconomyCompilerConfigurationFactory extends CompilerConfigurationFactory { @@ -44,7 +47,7 @@ public class EconomyCompilerConfigurationFactory extends CompilerConfigurationFa @Override public BackendMap createBackendMap() { - // the economy configuration only differs in the frontend, it reuses the "core" backend - return new DefaultBackendMap(CoreCompilerConfigurationFactory.NAME); + // the economy configuration only differs in the frontend, it reuses the "community" backend + return new DefaultBackendMap(CommunityCompilerConfigurationFactory.NAME); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index d1408c4c97c..ce458df79ac 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -25,33 +25,16 @@ package org.graalvm.compiler.hotspot; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; /** * Used to access native configuration details. */ -public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { - - /** - * Sentinel value to use for an {@linkplain InjectedParameter injected} - * {@link GraalHotSpotVMConfig} parameter to a {@linkplain Fold foldable} method. - */ - public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null; - - // this uses `1.9` which will give the correct result with `1.9`, `9`, `10` etc. - private final boolean isJDK8 = System.getProperty("java.specification.version").compareTo("1.9") < 0; - private final int jdkVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version")); - public final String osName = getHostOSName(); - public final String osArch = getHostArchitectureName(); - public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); - public final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux"); +public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase { GraalHotSpotVMConfig(HotSpotVMConfigStore store) { super(store); @@ -64,29 +47,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { assert check(); } - /** - * Gets the value of a static C++ field under two possible names. {@code name} is the preferred - * name and will be checked first. - * - * @param name fully qualified name of the field - * @param alternateName fully qualified alternate name of the field - * @param type the boxed type to which the constant value will be converted - * @param cppType if non-null, the expected C++ type of the field (e.g., {@code "HeapWord*"}) - * @return the value of the requested field - * @throws JVMCIError if the field is not static or not present - */ - public T getFieldValueWithAlternate(String name, String alternateName, Class type, String cppType) { - try { - return getFieldValue(name, type, cppType); - } catch (JVMCIError e) { - try { - return getFieldValue(alternateName, type, cppType); - } catch (JVMCIError e2) { - throw new JVMCIError("expected VM field not found: " + name + " or " + alternateName); - } - } - } - private final CompressEncoding oopEncoding; private final CompressEncoding klassEncoding; @@ -98,50 +58,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { return klassEncoding; } - /** - * Gets the host operating system name. - */ - private static String getHostOSName() { - String osName = System.getProperty("os.name"); - switch (osName) { - case "Linux": - osName = "linux"; - break; - case "SunOS": - osName = "solaris"; - break; - case "Mac OS X": - osName = "bsd"; - break; - default: - // Of course Windows is different... - if (osName.startsWith("Windows")) { - osName = "windows"; - } else { - throw new JVMCIError("Unexpected OS name: " + osName); - } - } - return osName; - } - - private static String getHostArchitectureName() { - String arch = System.getProperty("os.arch"); - switch (arch) { - case "x86_64": - arch = "amd64"; - break; - case "sparcv9": - arch = "sparc"; - break; - } - return arch; - } - - private final Integer intRequiredOnAMD64 = osArch.equals("amd64") ? null : 0; - private final Long longRequiredOnAMD64 = osArch.equals("amd64") ? null : 0L; - private final Integer intNotPresentInJDK8 = isJDK8 ? 0 : null; - private final Long longNotPresentInJDK8 = isJDK8 ? 0L : null; - public final boolean cAssertions = getConstant("ASSERT", Boolean.class); public final int codeEntryAlignment = getFlag("CodeEntryAlignment", Integer.class); @@ -157,6 +73,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int hugeMethodLimit = getFlag("HugeMethodLimit", Integer.class); public final boolean printInlining = getFlag("PrintInlining", Boolean.class); public final boolean inline = getFlag("Inline", Boolean.class); + public final boolean inlineNotify = versioned.inlineNotify; public final boolean useFastLocking = getFlag("JVMCIUseFastLocking", Boolean.class); public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class); public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class); @@ -168,7 +85,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class); public final boolean useAESIntrinsics = getFlag("UseAESIntrinsics", Boolean.class); public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class); - public final boolean useCRC32CIntrinsics = isJDK8 ? false : getFlag("UseCRC32CIntrinsics", Boolean.class); + public final boolean useCRC32CIntrinsics = versioned.useCRC32CIntrinsics; public final boolean threadLocalHandshakes = getFlag("ThreadLocalHandshakes", Boolean.class, false); private final boolean useMultiplyToLenIntrinsic = getFlag("UseMultiplyToLenIntrinsic", Boolean.class); @@ -216,6 +133,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { return useSquareToLenIntrinsic && squareToLen != 0; } + public boolean inlineNotify() { + return inlineNotify && notifyAddress != 0; + } + + public boolean inlineNotifyAll() { + return inlineNotify && notifyAllAddress != 0; + } + public final boolean useG1GC = getFlag("UseG1GC", Boolean.class); public final boolean useCMSGC = getFlag("UseConcMarkSweepGC", Boolean.class); @@ -383,7 +308,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int"); public final int threadObjectResultOffset = getFieldOffset("JavaThread::_vm_result", Integer.class, "oop"); public final int jvmciCountersThreadOffset = getFieldOffset("JavaThread::_jvmci_counters", Integer.class, "jlong*"); - public final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address", intNotPresentInJDK8); + public final int javaThreadReservedStackActivationOffset = versioned.javaThreadReservedStackActivationOffset; /** * An invalid value for {@link #rtldDefault}. @@ -504,14 +429,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int methodAccessFlagsOffset = getFieldOffset("Method::_access_flags", Integer.class, "AccessFlags"); public final int methodConstMethodOffset = getFieldOffset("Method::_constMethod", Integer.class, "ConstMethod*"); - public final int methodIntrinsicIdOffset = getFieldOffset("Method::_intrinsic_id", Integer.class, isJDK8 ? "u1" : "u2"); - public final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, isJDK8 ? "u1" : "u2"); + public final int methodIntrinsicIdOffset = versioned.methodIntrinsicIdOffset; + public final int methodFlagsOffset = versioned.methodFlagsOffset; public final int methodVtableIndexOffset = getFieldOffset("Method::_vtable_index", Integer.class, "int"); public final int methodCountersOffset = getFieldOffset("Method::_method_counters", Integer.class, "MethodCounters*"); public final int methodDataOffset = getFieldOffset("Method::_method_data", Integer.class, "MethodData*"); public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); - public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*"); + public final int methodCodeOffset = versioned.methodCodeOffset; public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class); public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class); @@ -522,8 +447,8 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int invocationCounterOffset = getFieldOffset("MethodCounters::_invocation_counter", Integer.class, "InvocationCounter"); public final int backedgeCounterOffset = getFieldOffset("MethodCounters::_backedge_counter", Integer.class, "InvocationCounter"); - public final int invocationCounterIncrement = getConstant("InvocationCounter::count_increment", Integer.class, intNotPresentInJDK8); - public final int invocationCounterShift = getConstant("InvocationCounter::count_shift", Integer.class, intNotPresentInJDK8); + public final int invocationCounterIncrement = versioned.invocationCounterIncrement; + public final int invocationCounterShift = versioned.invocationCounterShift; public final int nmethodEntryOffset = getFieldOffset("nmethod::_verified_entry_point", Integer.class, "address"); @@ -548,11 +473,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int"); - public final byte dirtyCardValue = jdkVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class) - : (jdkVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int")); - public final byte g1YoungCardValue = jdkVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class) - : (jdkVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) : getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int")); - public final long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*"); public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int"); @@ -560,17 +480,20 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { * This is the largest stack offset encodeable in an OopMapValue. Offsets larger than this will * throw an exception during code installation. */ - public final int maxOopMapStackOffset = getFieldValueWithAlternate("CompilerToVM::Data::_max_oop_map_stack_offset", "JVMCIRuntime::max_oop_map_stack_offset", Integer.class, "int"); + public final int maxOopMapStackOffset = getFieldValue("CompilerToVM::Data::_max_oop_map_stack_offset", Integer.class, "int"); public final long safepointPollingAddress = getFieldValue("os::_polling_page", Long.class, "address"); // G1 Collector Related Values. - public final int g1SATBQueueMarkingOffset = getConstant("G1ThreadLocalData::satb_mark_queue_active_offset", Integer.class); - public final int g1SATBQueueIndexOffset = getConstant("G1ThreadLocalData::satb_mark_queue_index_offset", Integer.class); - public final int g1SATBQueueBufferOffset = getConstant("G1ThreadLocalData::satb_mark_queue_buffer_offset", Integer.class); - public final int g1CardQueueIndexOffset = getConstant("G1ThreadLocalData::dirty_card_queue_index_offset", Integer.class); - public final int g1CardQueueBufferOffset = getConstant("G1ThreadLocalData::dirty_card_queue_buffer_offset", Integer.class); + public final byte dirtyCardValue = versioned.dirtyCardValue; + public final byte g1YoungCardValue = versioned.g1YoungCardValue; + + public final int g1SATBQueueMarkingOffset = versioned.g1SATBQueueMarkingOffset; + public final int g1SATBQueueIndexOffset = versioned.g1SATBQueueIndexOffset; + public final int g1SATBQueueBufferOffset = versioned.g1SATBQueueBufferOffset; + public final int g1CardQueueIndexOffset = versioned.g1CardQueueIndexOffset; + public final int g1CardQueueBufferOffset = versioned.g1CardQueueBufferOffset; public final int klassOffset = getFieldValue("java_lang_Class::_klass_offset", Integer.class, "int"); public final int arrayKlassOffset = getFieldValue("java_lang_Class::_array_klass_offset", Integer.class, "int"); @@ -636,7 +559,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { // FIXME This is only temporary until the GC code is changed. public final boolean inlineContiguousAllocationSupported = getFieldValue("CompilerToVM::Data::_supports_inline_contig_alloc", Boolean.class); public final long heapEndAddress = getFieldValue("CompilerToVM::Data::_heap_end_addr", Long.class, "HeapWord**"); - public final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, isJDK8 ? "HeapWord**" : "HeapWord* volatile*"); + public final long heapTopAddress = versioned.heapTopAddress; public final boolean cmsIncrementalMode = getFlag("CMSIncrementalMode", Boolean.class, false); @@ -646,8 +569,8 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address"); public final long uncommonTrapStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", Long.class, "address"); - public final long codeCacheLowBound = getFieldValue(isJDK8 ? "CompilerToVM::Data::CodeCache_low_bound" : "CodeCache::_low_bound", Long.class, "address"); - public final long codeCacheHighBound = getFieldValue(isJDK8 ? "CompilerToVM::Data::CodeCache_high_bound" : "CodeCache::_high_bound", Long.class, "address"); + public final long codeCacheLowBound = versioned.codeCacheLowBound; + public final long codeCacheHighBound = versioned.codeCacheHighBound; public final long aescryptEncryptBlockStub = getFieldValue("StubRoutines::_aescrypt_encryptBlock", Long.class, "address"); public final long aescryptDecryptBlockStub = getFieldValue("StubRoutines::_aescrypt_decryptBlock", Long.class, "address"); @@ -675,7 +598,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final long montgomerySquare = getFieldValue("StubRoutines::_montgomerySquare", Long.class, "address", longRequiredOnAMD64); public final long vectorizedMismatch = getFieldValue("StubRoutines::_vectorizedMismatch", Long.class, "address", 0L); - public final long throwDelayedStackOverflowErrorEntry = getFieldValue("StubRoutines::_throw_delayed_StackOverflowError_entry", Long.class, "address", longNotPresentInJDK8); + public final long throwDelayedStackOverflowErrorEntry = versioned.throwDelayedStackOverflowErrorEntry; public final long jbyteArraycopy = getFieldValue("StubRoutines::_jbyte_arraycopy", Long.class, "address"); public final long jshortArraycopy = getFieldValue("StubRoutines::_jshort_arraycopy", Long.class, "address"); @@ -718,6 +641,8 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final long exceptionHandlerForPcAddress = getAddress("JVMCIRuntime::exception_handler_for_pc"); public final long monitorenterAddress = getAddress("JVMCIRuntime::monitorenter"); public final long monitorexitAddress = getAddress("JVMCIRuntime::monitorexit"); + public final long notifyAddress = getAddress("JVMCIRuntime::object_notify", 0L); + public final long notifyAllAddress = getAddress("JVMCIRuntime::object_notifyAll", 0L); public final long throwAndPostJvmtiExceptionAddress = getAddress("JVMCIRuntime::throw_and_post_jvmti_exception"); public final long throwKlassExternalNameExceptionAddress = getAddress("JVMCIRuntime::throw_klass_external_name_exception"); public final long throwClassCastExceptionAddress = getAddress("JVMCIRuntime::throw_class_cast_exception"); @@ -735,7 +660,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final long registerFinalizerAddress = getAddress("SharedRuntime::register_finalizer"); public final long exceptionHandlerForReturnAddressAddress = getAddress("SharedRuntime::exception_handler_for_return_address"); public final long osrMigrationEndAddress = getAddress("SharedRuntime::OSR_migration_end"); - public final long enableStackReservedZoneAddress = getAddress("SharedRuntime::enable_stack_reserved_zone", longNotPresentInJDK8); + public final long enableStackReservedZoneAddress = versioned.enableStackReservedZoneAddress; public final long javaTimeMillisAddress = getAddress("os::javaTimeMillis"); public final long javaTimeNanosAddress = getAddress("os::javaTimeNanos"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java new file mode 100644 index 00000000000..0dc05e49c0d --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; + +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; + +/** + * This is a source with different versions for various JDKs. + */ +public abstract class GraalHotSpotVMConfigBase extends HotSpotVMConfigAccess { + + GraalHotSpotVMConfigBase(HotSpotVMConfigStore store) { + super(store); + assert this instanceof GraalHotSpotVMConfig; + versioned = new GraalHotSpotVMConfigVersioned(store); + } + + /** + * Contains values that are different between JDK versions. + */ + protected final GraalHotSpotVMConfigVersioned versioned; + + /** + * Sentinel value to use for an {@linkplain InjectedParameter injected} + * {@link GraalHotSpotVMConfig} parameter to a {@linkplain Fold foldable} method. + */ + public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null; + + public final String osName = getHostOSName(); + public final String osArch = getHostArchitectureName(); + public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); + public final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux"); + + /** + * Gets the host operating system name. + */ + private static String getHostOSName() { + String osName = System.getProperty("os.name"); + switch (osName) { + case "Linux": + osName = "linux"; + break; + case "SunOS": + osName = "solaris"; + break; + case "Mac OS X": + osName = "bsd"; + break; + default: + // Of course Windows is different... + if (osName.startsWith("Windows")) { + osName = "windows"; + } else { + throw new JVMCIError("Unexpected OS name: " + osName); + } + } + return osName; + } + + private static String getHostArchitectureName() { + String arch = System.getProperty("os.arch"); + switch (arch) { + case "x86_64": + arch = "amd64"; + break; + case "sparcv9": + arch = "sparc"; + break; + } + return arch; + } + + protected final Integer intRequiredOnAMD64 = osArch.equals("amd64") ? null : 0; + protected final Long longRequiredOnAMD64 = osArch.equals("amd64") ? null : 0L; +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java new file mode 100644 index 00000000000..81c9f975eca --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; + +/** + * This is a source with different versions for various JDKs. When modifying/adding a field in this + * class accessed from outside this class, be sure to update the field appropriately in all source + * files named {@code GraalHotSpotVMConfigVersioned.java}. + * + * Fields are grouped according to the most recent JBS issue showing why they are versioned. + * + * JDK Version: 11+ + */ +final class GraalHotSpotVMConfigVersioned extends HotSpotVMConfigAccess { + + GraalHotSpotVMConfigVersioned(HotSpotVMConfigStore store) { + super(store); + } + + // JDK-8073583 + final boolean useCRC32CIntrinsics = getFlag("UseCRC32CIntrinsics", Boolean.class); + + // JDK-8075171 + final boolean inlineNotify = getFlag("InlineNotify", Boolean.class); + + // JDK-8046936 + final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address"); + final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, "u2"); + final long throwDelayedStackOverflowErrorEntry = getFieldValue("StubRoutines::_throw_delayed_StackOverflowError_entry", Long.class, "address"); + final long enableStackReservedZoneAddress = getAddress("SharedRuntime::enable_stack_reserved_zone"); + + // JDK-8135085 + final int methodIntrinsicIdOffset = getFieldOffset("Method::_intrinsic_id", Integer.class, "u2"); + + // JDK-8151956 + final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, "CompiledMethod*"); + + // JDK-8059606 + final int invocationCounterIncrement = getConstant("InvocationCounter::count_increment", Integer.class); + final int invocationCounterShift = getConstant("InvocationCounter::count_shift", Integer.class); + + // JDK-8195142 + final byte dirtyCardValue = getConstant("CardTable::dirty_card", Byte.class); + final byte g1YoungCardValue = getConstant("G1CardTable::g1_young_gen", Byte.class); + + // JDK-8201318 + final int g1SATBQueueMarkingOffset = getConstant("G1ThreadLocalData::satb_mark_queue_active_offset", Integer.class); + final int g1SATBQueueIndexOffset = getConstant("G1ThreadLocalData::satb_mark_queue_index_offset", Integer.class); + final int g1SATBQueueBufferOffset = getConstant("G1ThreadLocalData::satb_mark_queue_buffer_offset", Integer.class); + final int g1CardQueueIndexOffset = getConstant("G1ThreadLocalData::dirty_card_queue_index_offset", Integer.class); + final int g1CardQueueBufferOffset = getConstant("G1ThreadLocalData::dirty_card_queue_buffer_offset", Integer.class); + + // JDK-8033552 + final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, "HeapWord* volatile*"); + + // JDK-8015774 + final long codeCacheLowBound = getFieldValue("CodeCache::_low_bound", Long.class, "address"); + final long codeCacheHighBound = getFieldValue("CodeCache::_high_bound", Long.class, "address"); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java index 8b358c1f249..10063895972 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java @@ -64,11 +64,11 @@ import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.SuitesProvider; import org.graalvm.compiler.word.Word; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; -import org.graalvm.word.Pointer; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.word.Pointer; import jdk.vm.ci.code.CompilationRequest; import jdk.vm.ci.code.CompiledCode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java index 825f2822a69..8174a67d5a2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java @@ -221,6 +221,10 @@ public class HotSpotCompiledCodeBuilder { List sourcePositionSites = new ArrayList<>(); for (SourceMapping source : target.getSourceMappings()) { NodeSourcePosition sourcePosition = source.getSourcePosition(); + if (sourcePosition.isPlaceholder() || sourcePosition.isSubstitution()) { + // HotSpot doesn't understand any of the special positions so just drop them. + continue; + } assert sourcePosition.verify(); sourcePosition = sourcePosition.trim(); /* diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java index c13813ff1f5..57492d6c218 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java @@ -28,7 +28,7 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; import java.util.Arrays; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.GraalError; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java index d316d0050bf..afb6ecc3a1b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java @@ -27,7 +27,7 @@ import jdk.vm.ci.meta.InvokeTarget; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.hotspot.stubs.Stub; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * The details required to link a HotSpot runtime or stub call. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java index 5288ae7b762..3805a1c6dbe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java @@ -25,13 +25,13 @@ package org.graalvm.compiler.hotspot; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.CallingConvention.Type; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java index c160cc0878c..8d95fa2d8b5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java @@ -38,9 +38,9 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.GraalCompiler; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.util.CompilationAlarm; -import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Activation; +import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.hotspot.CompilationCounters.Options; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; @@ -105,17 +105,16 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler { @Override public CompilationRequestResult compileMethod(CompilationRequest request) { - return compileMethod(request, true); + return compileMethod(request, true, graalRuntime.getOptions()); } @SuppressWarnings("try") - CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault) { + CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault, OptionValues options) { if (graalRuntime.isShutdown()) { return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false); } ResolvedJavaMethod method = request.getMethod(); - OptionValues options = graalRuntime.getOptions(method); if (graalRuntime.isBootstrapping()) { if (DebugOptions.BootstrapInitializeOnly.getValue(options)) { @@ -282,13 +281,6 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler { return suite; } - public Object mbean() { - if (graalRuntime instanceof HotSpotGraalRuntime) { - return ((HotSpotGraalRuntime) graalRuntime).getMBean(); - } - return null; - } - /** * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format * string {@code "%H.%n(%p)"}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java index b5c9ff861fc..fc7c852513c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java @@ -26,9 +26,8 @@ import static jdk.vm.ci.common.InitTimer.timer; import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX; import java.io.PrintStream; -import java.util.Collections; -import java.util.Map; +import org.graalvm.compiler.api.runtime.GraalRuntime; import org.graalvm.compiler.debug.MethodFilter; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -36,7 +35,6 @@ import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.options.OptionsParser; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; -import org.graalvm.compiler.serviceprovider.JDK9Method; import jdk.vm.ci.common.InitTimer; import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; @@ -49,21 +47,7 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto private static MethodFilter[] graalCompileOnlyFilter; private static boolean compileGraalWithC1Only; - /** - * Module containing {@link HotSpotJVMCICompilerFactory}. - */ - private Object jvmciModule; - - /** - * Module containing {@link HotSpotGraalCompilerFactory}. - */ - private Object graalModule; - - /** - * Module containing the {@linkplain CompilerConfigurationFactory#selectFactory selected} - * configuration. - */ - private Object compilerConfigurationModule; + private IsGraalPredicate isGraalPredicate; private final HotSpotGraalJVMCIServiceLocator locator; @@ -87,10 +71,7 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto assert options == null : "cannot select " + getClass() + " service more than once"; options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; initializeGraalCompilePolicyFields(options); - if (!JDK9Method.Java8OrEarlier) { - jvmciModule = JDK9Method.getModule(HotSpotJVMCICompilerFactory.class); - graalModule = JDK9Method.getModule(HotSpotGraalCompilerFactory.class); - } + isGraalPredicate = compileGraalWithC1Only ? new IsGraalPredicate() : null; /* * Exercise this code path early to encourage loading now. This doesn't solve problem of * deadlock during class loading but seems to eliminate it in practice. @@ -134,10 +115,10 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto @Override public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) { CompilerConfigurationFactory factory = CompilerConfigurationFactory.selectFactory(null, options); - if (!JDK9Method.Java8OrEarlier) { - compilerConfigurationModule = JDK9Method.getModule(factory.getClass()); + if (isGraalPredicate != null) { + isGraalPredicate.onCompilerConfigurationFactorySelection(factory); } - HotSpotGraalCompiler compiler = createCompiler(runtime, options, factory); + HotSpotGraalCompiler compiler = createCompiler("VM", runtime, options, factory); // Only the HotSpotGraalRuntime associated with the compiler created via // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving // VM events. @@ -149,14 +130,17 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto * Creates a new {@link HotSpotGraalRuntime} object and a new {@link HotSpotGraalCompiler} and * returns the latter. * + * @param runtimeNameQualifier a qualifier to be added to the {@linkplain GraalRuntime#getName() + * name} of the {@linkplain HotSpotGraalCompiler#getGraalRuntime() runtime} created + * by this method * @param runtime the JVMCI runtime on which the {@link HotSpotGraalRuntime} is built * @param compilerConfigurationFactory factory for the {@link CompilerConfiguration} */ @SuppressWarnings("try") - public static HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime, OptionValues options, CompilerConfigurationFactory compilerConfigurationFactory) { + public static HotSpotGraalCompiler createCompiler(String runtimeNameQualifier, JVMCIRuntime runtime, OptionValues options, CompilerConfigurationFactory compilerConfigurationFactory) { HotSpotJVMCIRuntime jvmciRuntime = (HotSpotJVMCIRuntime) runtime; try (InitTimer t = timer("HotSpotGraalRuntime.")) { - HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(jvmciRuntime, compilerConfigurationFactory, options); + HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(runtimeNameQualifier, jvmciRuntime, compilerConfigurationFactory, options); return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime, graalRuntime.getOptions()); } } @@ -187,54 +171,11 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory"); } - static final ClassLoader JVMCI_LOADER = HotSpotGraalCompilerFactory.class.getClassLoader(); - - /* - * This method is static so it can be exercised during initialization. - */ private CompilationLevel adjustCompilationLevelInternal(Class declaringClass, String name, String signature, CompilationLevel level) { if (compileGraalWithC1Only) { if (level.ordinal() > CompilationLevel.Simple.ordinal()) { - if (JDK9Method.Java8OrEarlier) { - if (JVMCI_LOADER != null) { - // When running with +UseJVMCIClassLoader all classes in - // the JVMCI loader should be compiled with C1. - try { - if (declaringClass.getClassLoader() == JVMCI_LOADER) { - return CompilationLevel.Simple; - } - } catch (SecurityException e) { - // This is definitely not a JVMCI or Graal class - } - } else { - // JVMCI and Graal are on the bootclasspath so match based on the package. - String declaringClassName = declaringClass.getName(); - if (declaringClassName.startsWith("jdk.vm.ci")) { - return CompilationLevel.Simple; - } - if (declaringClassName.startsWith("org.graalvm.") && - (declaringClassName.startsWith("org.graalvm.compiler.") || - declaringClassName.startsWith("org.graalvm.collections.") || - declaringClassName.startsWith("org.graalvm.compiler.word.") || - declaringClassName.startsWith("org.graalvm.graphio."))) { - return CompilationLevel.Simple; - } - if (declaringClassName.startsWith("com.oracle.graal") && - (declaringClassName.startsWith("com.oracle.graal.enterprise") || - declaringClassName.startsWith("com.oracle.graal.vector") || - declaringClassName.startsWith("com.oracle.graal.asm"))) { - return CompilationLevel.Simple; - } - } - } else { - try { - Object module = JDK9Method.getModule(declaringClass); - if (jvmciModule == module || graalModule == module || compilerConfigurationModule == module) { - return CompilationLevel.Simple; - } - } catch (Throwable e) { - throw new InternalError(e); - } + if (isGraalPredicate.apply(declaringClass)) { + return CompilationLevel.Simple; } } } @@ -258,11 +199,4 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto } return level; } - - public Map mbeans() { - HotSpotGraalCompiler compiler = createCompiler(HotSpotJVMCIRuntime.runtime()); - String name = "org.graalvm.compiler.hotspot:type=Options"; - Object bean = ((HotSpotGraalRuntime) compiler.getGraalRuntime()).getMBean(); - return Collections.singletonMap(name, bean); - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java deleted file mode 100644 index c0c91e29025..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 org.graalvm.compiler.hotspot; - -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import jdk.vm.ci.hotspot.HotSpotCompilationRequest; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.vm.ci.meta.MetaUtil; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.JVMCI; - -import org.graalvm.compiler.debug.DebugOptions; -import org.graalvm.compiler.options.OptionDescriptor; -import org.graalvm.compiler.options.OptionDescriptors; -import org.graalvm.compiler.options.OptionKey; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.options.OptionsParser; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; - -public final class HotSpotGraalMBean implements javax.management.DynamicMBean { - private static Object mBeanServerField; - private final HotSpotGraalCompiler compiler; - private final OptionValues options; - private final EconomicMap, Object> changes; - private final EconomicSet methodDumps; - private volatile EconomicSet> loaders; - private javax.management.ObjectName registered; - private OptionValues cachedOptions; - - private HotSpotGraalMBean(HotSpotGraalCompiler compiler, OptionValues options) { - this.compiler = compiler; - this.options = options; - this.changes = EconomicMap.create(); - this.methodDumps = EconomicSet.create(); - EconomicSet> systemLoaderSet = EconomicSet.create(RefEquivalence.INSTANCE); - systemLoaderSet.add(new WeakReference<>(ClassLoader.getSystemClassLoader())); - this.loaders = systemLoaderSet; - } - - private static boolean isMXServerOn() { - if (mBeanServerField == null) { - try { - final Field field = java.lang.management.ManagementFactory.class.getDeclaredField("platformMBeanServer"); - field.setAccessible(true); - mBeanServerField = field; - } catch (Exception ex) { - mBeanServerField = java.lang.management.ManagementFactory.class; - } - } - if (mBeanServerField instanceof Field) { - try { - return ((Field) mBeanServerField).get(null) != null; - } catch (Exception ex) { - return true; - } - } else { - return false; - } - } - - public static HotSpotGraalMBean create(HotSpotGraalCompiler compiler) { - OptionValues options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; - HotSpotGraalMBean mbean = new HotSpotGraalMBean(compiler, options); - return mbean; - } - - public javax.management.ObjectName ensureRegistered(boolean check) { - for (int cnt = 0;; cnt++) { - if (registered != null) { - return registered; - } - if (check && !isMXServerOn()) { - return null; - } - try { - javax.management.MBeanServer mbs = java.lang.management.ManagementFactory.getPlatformMBeanServer(); - javax.management.ObjectName name = new javax.management.ObjectName("org.graalvm.compiler.hotspot:type=Options" + (cnt == 0 ? "" : cnt)); - mbs.registerMBean(this, name); - registered = name; - break; - } catch (javax.management.MalformedObjectNameException | javax.management.MBeanRegistrationException | javax.management.NotCompliantMBeanException ex) { - throw new IllegalStateException(ex); - } catch (javax.management.InstanceAlreadyExistsException ex) { - continue; - } - } - return registered; - } - - public OptionValues optionsFor(OptionValues initialValues, ResolvedJavaMethod forMethod) { - ensureRegistered(true); - if (forMethod instanceof HotSpotResolvedJavaMethod) { - HotSpotResolvedObjectType type = ((HotSpotResolvedJavaMethod) forMethod).getDeclaringClass(); - if (type instanceof HotSpotResolvedJavaType) { - Class clazz = ((HotSpotResolvedJavaType) type).mirror(); - Reference addNewRef = new WeakReference<>(clazz.getClassLoader()); - if (!loaders.contains(addNewRef)) { - EconomicSet> newLoaders = EconomicSet.create(RefEquivalence.INSTANCE, loaders); - newLoaders.add(addNewRef); - this.loaders = newLoaders; - } - } - } - return currentMap(initialValues, forMethod); - } - - private OptionValues currentMap(OptionValues initialValues, ResolvedJavaMethod method) { - if (changes.isEmpty() && methodDumps.isEmpty()) { - return initialValues; - } - OptionValues current = cachedOptions; - if (current == null) { - current = new OptionValues(initialValues, changes); - cachedOptions = current; - } - if (method != null) { - for (Dump request : methodDumps) { - final String clazzName = method.getDeclaringClass().getName(); - if (method.getName().equals(request.method) && clazzName.equals(request.clazz)) { - current = new OptionValues(current, DebugOptions.Dump, request.filter, - DebugOptions.PrintGraphHost, request.host, - DebugOptions.PrintBinaryGraphPort, request.port); - break; - } - } - } - return current; - } - - @Override - public Object getAttribute(String attribute) { - UnmodifiableEconomicMap, Object> map = currentMap(options, null).getMap(); - for (OptionKey k : map.getKeys()) { - if (k.getName().equals(attribute)) { - return map.get(k); - } - } - return null; - } - - @Override - public void setAttribute(javax.management.Attribute attribute) throws javax.management.AttributeNotFoundException { - javax.management.Attribute newAttr = setImpl(attribute); - if (newAttr == null) { - throw new javax.management.AttributeNotFoundException(); - } - } - - private javax.management.Attribute setImpl(javax.management.Attribute attribute) { - cachedOptions = null; - for (OptionDescriptor option : allOptionDescriptors()) { - if (option.getName().equals(attribute.getName())) { - changes.put(option.getOptionKey(), attribute.getValue()); - return attribute; - } - } - return null; - } - - @Override - public javax.management.AttributeList getAttributes(String[] names) { - javax.management.AttributeList list = new javax.management.AttributeList(); - for (String name : names) { - Object value = getAttribute(name); - if (value != null) { - list.add(new javax.management.Attribute(name, value)); - } - } - return list; - } - - @Override - public javax.management.AttributeList setAttributes(javax.management.AttributeList attributes) { - javax.management.AttributeList setOk = new javax.management.AttributeList(); - for (javax.management.Attribute attr : attributes.asList()) { - javax.management.Attribute newAttr = setImpl(attr); - if (newAttr != null) { - setOk.add(newAttr); - } - } - return setOk; - } - - @Override - public Object invoke(String actionName, Object[] params, String[] signature) throws javax.management.MBeanException, javax.management.ReflectionException { - if ("dumpMethod".equals(actionName)) { - try { - String className = param(params, 0, "className", String.class, null); - String methodName = param(params, 1, "methodName", String.class, null); - String filter = param(params, 2, "filter", String.class, ":3"); - String host = param(params, 3, "host", String.class, "localhost"); - Number port = param(params, 4, "port", Number.class, 4445); - dumpMethod(className, methodName, filter, host, port.intValue()); - } catch (Exception ex) { - throw new javax.management.ReflectionException(ex); - } - } - return null; - } - - private static T param(Object[] arr, int index, String name, Class type, T defaultValue) { - Object value = arr.length > index ? arr[index] : null; - if (value == null || (value instanceof String && ((String) value).isEmpty())) { - if (defaultValue == null) { - throw new IllegalArgumentException(name + " must be specified"); - } - value = defaultValue; - } - if (type.isInstance(value)) { - return type.cast(value); - } - throw new IllegalArgumentException("Expecting " + type.getName() + " for " + name + " but was " + value); - } - - public void dumpMethod(String className, String methodName, String filter, String host, int port) throws javax.management.MBeanException { - String jvmName = MetaUtil.toInternalName(className); - methodDumps.add(new Dump(host, port, jvmName, methodName, filter)); - - ClassNotFoundException last = null; - EconomicSet> found = EconomicSet.create(); - Iterator> it = loaders.iterator(); - while (it.hasNext()) { - Reference ref = it.next(); - ClassLoader loader = ref.get(); - if (loader == null) { - it.remove(); - continue; - } - try { - Class clazz = Class.forName(className, false, loader); - if (found.add(clazz)) { - ResolvedJavaType type = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(clazz); - if (compiler != null) { - for (ResolvedJavaMethod method : type.getDeclaredMethods()) { - if (methodName.equals(method.getName()) && method instanceof HotSpotResolvedJavaMethod) { - HotSpotResolvedJavaMethod hotSpotMethod = (HotSpotResolvedJavaMethod) method; - compiler.compileMethod(new HotSpotCompilationRequest(hotSpotMethod, -1, 0L), false); - } - } - } - } - } catch (ClassNotFoundException ex) { - last = ex; - } - } - if (found.isEmpty()) { - throw new javax.management.MBeanException(last, "Cannot find class " + className + " to schedule recompilation"); - } - } - - @Override - public javax.management.MBeanInfo getMBeanInfo() { - List attrs = new ArrayList<>(); - for (OptionDescriptor descr : allOptionDescriptors()) { - attrs.add(new javax.management.MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false)); - } - javax.management.MBeanOperationInfo[] ops = { - new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{ - new javax.management.MBeanParameterInfo("className", "java.lang.String", "Class to observe"), - new javax.management.MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"), - }, "void", javax.management.MBeanOperationInfo.ACTION), - new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{ - new javax.management.MBeanParameterInfo("className", "java.lang.String", "Class to observe"), - new javax.management.MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"), - new javax.management.MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"), - }, "void", javax.management.MBeanOperationInfo.ACTION), - new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{ - new javax.management.MBeanParameterInfo("className", "java.lang.String", "Class to observe"), - new javax.management.MBeanParameterInfo("methodName", "java.lang.String", "Method to observe"), - new javax.management.MBeanParameterInfo("filter", "java.lang.String", "The parameter for Dump option"), - new javax.management.MBeanParameterInfo("host", "java.lang.String", "The host where the IGV tool is running at"), - new javax.management.MBeanParameterInfo("port", "int", "The port where the IGV tool is listening at"), - }, "void", javax.management.MBeanOperationInfo.ACTION) - }; - - return new javax.management.MBeanInfo( - HotSpotGraalMBean.class.getName(), - "Graal", - attrs.toArray(new javax.management.MBeanAttributeInfo[attrs.size()]), - null, ops, null); - } - - private static Iterable allOptionDescriptors() { - List arr = new ArrayList<>(); - for (OptionDescriptors set : OptionsParser.getOptionsLoader()) { - for (OptionDescriptor descr : set) { - arr.add(descr); - } - } - return arr; - } - - private static final class Dump { - final String host; - final int port; - final String clazz; - final String method; - final String filter; - - Dump(String host, int port, String clazz, String method, String filter) { - this.host = host; - this.port = port; - this.clazz = clazz; - this.method = method; - this.filter = filter; - } - } - - private static final class RefEquivalence extends Equivalence { - static final Equivalence INSTANCE = new RefEquivalence(); - - private RefEquivalence() { - } - - @Override - public boolean equals(Object a, Object b) { - Reference refA = (Reference) a; - Reference refB = (Reference) b; - return Objects.equals(refA.get(), refB.get()); - } - - @Override - public int hashCode(Object o) { - Reference ref = (Reference) o; - Object obj = ref.get(); - return obj == null ? 0 : obj.hashCode(); - } - - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalManagementRegistration.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalManagementRegistration.java new file mode 100644 index 00000000000..1d601e4b7c3 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalManagementRegistration.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 org.graalvm.compiler.hotspot; + +/** + * Communicates with an MBean providing a JMX interface to a {@link HotSpotGraalRuntime} instance. + * The MBean will be dynamically created when a JMX client attaches or some other event causes the + * platform MBean server to be started. + */ +public interface HotSpotGraalManagementRegistration { + + /** + * Completes the initialization of this registration by recording the + * {@link HotSpotGraalRuntime} the MBean will provide an JMX interface to. + */ + void initialize(HotSpotGraalRuntime runtime); + + /** + * Polls this registration to see if the MBean is registered in a MBean server. + * + * @param sync synchronize with other threads that may be processing this registration. This is + * useful when the caller knows the server is active (e.g., it has a reference to + * server) and expects this poll to therefore return a non-null value. + * @return an {@link javax.management.ObjectName} that can be used to access the MBean or + * {@code null} if the MBean has not been registered with an MBean server (e.g., no JMX + * client has attached to the VM) + */ + Object poll(boolean sync); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java index 0d048bcda0d..655258a258c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java @@ -30,14 +30,12 @@ import java.io.IOException; import java.util.Map; import java.util.Properties; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.options.OptionValuesAccess; import org.graalvm.compiler.options.OptionsParser; -import org.graalvm.compiler.serviceprovider.ServiceProvider; import jdk.vm.ci.common.InitTimer; @@ -45,8 +43,7 @@ import jdk.vm.ci.common.InitTimer; * The {@link #HOTSPOT_OPTIONS} value contains the options values initialized in a HotSpot VM. The * values are set via system properties with the {@value #GRAAL_OPTION_PROPERTY_PREFIX} prefix. */ -@ServiceProvider(OptionValuesAccess.class) -public class HotSpotGraalOptionValues implements OptionValuesAccess { +public class HotSpotGraalOptionValues { /** * The name of the system property specifying a file containing extra Graal option settings. @@ -131,9 +128,4 @@ public class HotSpotGraalOptionValues implements OptionValuesAccess { return new OptionValues(values); } } - - @Override - public OptionValues getOptions() { - return HOTSPOT_OPTIONS; - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index adb5c431b36..cd8fa1697e4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -33,9 +33,12 @@ import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.runtime.GraalRuntime; import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; @@ -45,6 +48,7 @@ import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Description; import org.graalvm.compiler.debug.DebugHandlersFactory; +import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.debug.DiagnosticsOutputDirectory; import org.graalvm.compiler.debug.GlobalMetrics; import org.graalvm.compiler.debug.GraalError; @@ -54,19 +58,31 @@ import org.graalvm.compiler.hotspot.CompilerConfigurationFactory.BackendMap; import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.nodes.spi.StampProvider; +import org.graalvm.compiler.options.EnumOptionKey; +import org.graalvm.compiler.options.OptionDescriptor; +import org.graalvm.compiler.options.OptionDescriptors; +import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.options.OptionsParser; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.replacements.SnippetCounter; import org.graalvm.compiler.replacements.SnippetCounter.Group; import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.stack.StackIntrospection; import jdk.vm.ci.common.InitTimer; +import jdk.vm.ci.hotspot.HotSpotCompilationRequest; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.JVMCI; import jdk.vm.ci.runtime.JVMCIBackend; //JaCoCo Exclude @@ -88,6 +104,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { return true; } + private final String runtimeName; private final HotSpotBackend hostBackend; private final GlobalMetrics metricValues = new GlobalMetrics(); private final List snippetCounterGroups; @@ -96,25 +113,42 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { private final GraalHotSpotVMConfig config; - private final OptionValues options; + /** + * The options can be {@linkplain #setOptionValues(String[], String[]) updated} by external + * interfaces such as JMX. This comes with the risk that inconsistencies can arise as an + * {@link OptionValues} object can be cached by various parts of Graal instead of always + * obtaining them from this object. However, concurrent updates are never lost. + */ + private AtomicReference optionsRef = new AtomicReference<>(); + + private final HotSpotGraalCompiler compiler; + private final DiagnosticsOutputDirectory outputDirectory; private final Map compilationProblemsPerAction; - private final HotSpotGraalMBean mBean; /** + * @param nameQualifier a qualifier to be added to this runtime's {@linkplain #getName() name} * @param compilerConfigurationFactory factory for the compiler configuration * {@link CompilerConfigurationFactory#selectFactory(String, OptionValues)} */ @SuppressWarnings("try") - HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory, OptionValues initialOptions) { + HotSpotGraalRuntime(String nameQualifier, HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory, OptionValues initialOptions) { + this.runtimeName = getClass().getSimpleName() + ":" + nameQualifier; HotSpotVMConfigStore store = jvmciRuntime.getConfigStore(); config = GeneratePIC.getValue(initialOptions) ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store); // Only set HotSpotPrintInlining if it still has its default value (false). if (GraalOptions.HotSpotPrintInlining.getValue(initialOptions) == false && config.printInlining) { - options = new OptionValues(initialOptions, HotSpotPrintInlining, true); + optionsRef.set(new OptionValues(initialOptions, HotSpotPrintInlining, true)); } else { - options = initialOptions; + optionsRef.set(initialOptions); + } + OptionValues options = optionsRef.get(); + + if (config.useCMSGC) { + // Graal doesn't work with the CMS collector (e.g. GR-6777) + // and is deprecated (http://openjdk.java.net/jeps/291). + throw new GraalError("Graal does not support the CMS collector"); } outputDirectory = new DiagnosticsOutputDirectory(options); @@ -122,8 +156,11 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { snippetCounterGroups = GraalOptions.SnippetCounters.getValue(options) ? new ArrayList<>() : null; CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration(); - HotSpotGraalCompiler compiler = new HotSpotGraalCompiler(jvmciRuntime, this, initialOptions); - this.mBean = createHotSpotGraalMBean(compiler); + compiler = new HotSpotGraalCompiler(jvmciRuntime, this, options); + management = GraalServices.loadSingle(HotSpotGraalManagementRegistration.class, false); + if (management != null) { + management.initialize(this); + } BackendMap backendMap = compilerConfigurationFactory.createBackendMap(); @@ -172,14 +209,6 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { bootstrapJVMCI = config.getFlag("BootstrapJVMCI", Boolean.class); } - private static HotSpotGraalMBean createHotSpotGraalMBean(HotSpotGraalCompiler compiler) { - try { - return HotSpotGraalMBean.create(compiler); - } catch (LinkageError ex) { - return null; - } - } - private HotSpotBackend registerBackend(HotSpotBackend backend) { Class arch = backend.getTarget().arch.getClass(); HotSpotBackend oldValue = backends.put(arch, backend); @@ -199,24 +228,35 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { @Override public DebugContext openDebugContext(OptionValues compilationOptions, CompilationIdentifier compilationId, Object compilable, Iterable factories) { + if (management != null && management.poll(false) != null) { + if (compilable instanceof HotSpotResolvedJavaMethod) { + HotSpotResolvedObjectType type = ((HotSpotResolvedJavaMethod) compilable).getDeclaringClass(); + if (type instanceof HotSpotResolvedJavaType) { + Class clazz = ((HotSpotResolvedJavaType) type).mirror(); + try { + ClassLoader cl = clazz.getClassLoader(); + if (cl != null) { + loaders.add(cl); + } + } catch (SecurityException e) { + // This loader can obviously not be used for resolving class names + } + } + } + } Description description = new Description(compilable, compilationId.toString(CompilationIdentifier.Verbosity.ID)); return DebugContext.create(compilationOptions, description, metricValues, DEFAULT_LOG_STREAM, factories); } @Override public OptionValues getOptions() { - return mBean == null ? options : mBean.optionsFor(options, null); + return optionsRef.get(); } @Override - public OptionValues getOptions(ResolvedJavaMethod forMethod) { - return mBean == null ? options : mBean.optionsFor(options, forMethod); - } - - @Override - public Group createSnippetCounterGroup(String name) { + public Group createSnippetCounterGroup(String groupName) { if (snippetCounterGroups != null) { - Group group = new Group(name); + Group group = new Group(groupName); snippetCounterGroups.add(group); return group; } @@ -225,7 +265,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { @Override public String getName() { - return getClass().getSimpleName(); + return runtimeName; } @SuppressWarnings("unchecked") @@ -234,7 +274,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { if (clazz == RuntimeProvider.class) { return (T) this; } else if (clazz == OptionValues.class) { - return (T) options; + return (T) optionsRef.get(); } else if (clazz == StackIntrospection.class) { return (T) this; } else if (clazz == SnippetReflectionProvider.class) { @@ -265,14 +305,14 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { * @param phase the execution phase being entered */ void phaseTransition(String phase) { - if (Options.UseCompilationStatistics.getValue(options)) { + if (Options.UseCompilationStatistics.getValue(optionsRef.get())) { CompilationStatistics.clear(phase); } } void shutdown() { shutdown = true; - metricValues.print(options); + metricValues.print(optionsRef.get()); phaseTransition("final"); @@ -281,7 +321,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { TTY.out().out().println(group); } } - BenchmarkCounters.shutdown(runtime(), options, runtimeStartTime); + BenchmarkCounters.shutdown(runtime(), optionsRef.get(), runtimeStartTime); outputDirectory.close(); } @@ -317,7 +357,193 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { return compilationProblemsPerAction; } - Object getMBean() { - return mBean; + // ------- Management interface --------- + + private final HotSpotGraalManagementRegistration management; + + /** + * @returns the management object for this runtime or {@code null} + */ + public HotSpotGraalManagementRegistration getManagement() { + return management; + } + + /** + * Set of weak references to {@link ClassLoader}s available for resolving class names present in + * management {@linkplain #invokeManagementAction(String, Object[]) action} arguments. + */ + private final WeakClassLoaderSet loaders = new WeakClassLoaderSet(ClassLoader.getSystemClassLoader()); + + /** + * Sets or updates this object's {@linkplain #getOptions() options} from {@code names} and + * {@code values}. + * + * @param values the values to set. The empty string represents {@code null} which resets an + * option to its default value. For string type options, a non-empty value must be + * enclosed in double quotes. + * @return an array of Strings where the element at index i is {@code names[i]} if setting the + * denoted option succeeded, {@code null} if the option is unknown otherwise an error + * message describing the failure to set the option + */ + public String[] setOptionValues(String[] names, String[] values) { + EconomicMap optionDescriptors = getOptionDescriptors(); + EconomicMap, Object> newValues = EconomicMap.create(names.length); + EconomicSet> resetValues = EconomicSet.create(names.length); + String[] result = new String[names.length]; + for (int i = 0; i < names.length; i++) { + String name = names[i]; + OptionDescriptor option = optionDescriptors.get(name); + if (option != null) { + String svalue = values[i]; + Class optionValueType = option.getOptionValueType(); + OptionKey optionKey = option.getOptionKey(); + if (svalue == null || svalue.isEmpty() && !(optionKey instanceof EnumOptionKey)) { + resetValues.add(optionKey); + result[i] = name; + } else { + String valueToParse; + if (optionValueType == String.class) { + if (svalue.length() < 2 || svalue.charAt(0) != '"' || svalue.charAt(svalue.length() - 1) != '"') { + result[i] = "Invalid value for String option '" + name + "': must be the empty string or be enclosed in double quotes: " + svalue; + continue; + } else { + valueToParse = svalue.substring(1, svalue.length() - 1); + } + } else { + valueToParse = svalue; + } + try { + OptionsParser.parseOption(name, valueToParse, newValues, OptionsParser.getOptionsLoader()); + result[i] = name; + } catch (IllegalArgumentException e) { + result[i] = e.getMessage(); + continue; + } + } + } else { + result[i] = null; + } + } + + OptionValues currentOptions; + OptionValues newOptions; + do { + currentOptions = optionsRef.get(); + UnmodifiableMapCursor, Object> cursor = currentOptions.getMap().getEntries(); + while (cursor.advance()) { + OptionKey key = cursor.getKey(); + if (!resetValues.contains(key) && !newValues.containsKey(key)) { + newValues.put(key, OptionValues.decodeNull(cursor.getValue())); + } + } + newOptions = new OptionValues(newValues); + } while (!optionsRef.compareAndSet(currentOptions, newOptions)); + + return result; + } + + /** + * Gets the values for the options corresponding to {@code names} encoded as strings. The empty + * string represents {@code null}. For string type options, non-{@code null} values will be + * enclosed in double quotes. + * + * @param names a list of option names + * @return the values for each named option. If an element in {@code names} does not denote an + * existing option, the corresponding element in the returned array will be {@code null} + */ + public String[] getOptionValues(String... names) { + String[] values = new String[names.length]; + EconomicMap optionDescriptors = getOptionDescriptors(); + for (int i = 0; i < names.length; i++) { + OptionDescriptor option = optionDescriptors.get(names[i]); + if (option != null) { + OptionKey optionKey = option.getOptionKey(); + Object value = optionKey.getValue(getOptions()); + String svalue; + if (option.getOptionValueType() == String.class && value != null) { + svalue = "\"" + value + "\""; + } else if (value == null) { + svalue = ""; + } else { + svalue = String.valueOf(value); + } + values[i] = svalue; + } else { + // null denotes the option does not exist + values[i] = null; + } + } + return values; + } + + private static EconomicMap getOptionDescriptors() { + EconomicMap result = EconomicMap.create(); + for (OptionDescriptors set : OptionsParser.getOptionsLoader()) { + for (OptionDescriptor option : set) { + result.put(option.getName(), option); + } + } + return result; + } + + private void dumpMethod(String className, String methodName, String filter, String host, int port) throws Exception { + EconomicSet failures = EconomicSet.create(); + EconomicSet> found = loaders.resolve(className, failures); + if (found.isEmpty()) { + ClassNotFoundException cause = failures.isEmpty() ? new ClassNotFoundException(className) : failures.iterator().next(); + throw new Exception("Cannot find class " + className + " to schedule recompilation", cause); + } + for (Class clazz : found) { + ResolvedJavaType type = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(clazz); + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (methodName.equals(method.getName()) && method instanceof HotSpotResolvedJavaMethod) { + HotSpotResolvedJavaMethod hotSpotMethod = (HotSpotResolvedJavaMethod) method; + dumpMethod(hotSpotMethod, filter, host, port); + } + } + } + } + + private void dumpMethod(HotSpotResolvedJavaMethod hotSpotMethod, String filter, String host, int port) throws Exception { + EconomicMap, Object> extra = EconomicMap.create(); + extra.put(DebugOptions.Dump, filter); + extra.put(DebugOptions.PrintGraphHost, host); + extra.put(DebugOptions.PrintBinaryGraphPort, port); + OptionValues compileOptions = new OptionValues(getOptions(), extra); + compiler.compileMethod(new HotSpotCompilationRequest(hotSpotMethod, -1, 0L), false, compileOptions); + } + + public Object invokeManagementAction(String actionName, Object[] params) throws Exception { + if ("dumpMethod".equals(actionName)) { + if (params.length != 0 && params[0] instanceof HotSpotResolvedJavaMethod) { + HotSpotResolvedJavaMethod method = param(params, 0, "method", HotSpotResolvedJavaMethod.class, null); + String filter = param(params, 1, "filter", String.class, ":3"); + String host = param(params, 2, "host", String.class, "localhost"); + Number port = param(params, 3, "port", Number.class, 4445); + dumpMethod(method, filter, host, port.intValue()); + } else { + String className = param(params, 0, "className", String.class, null); + String methodName = param(params, 1, "methodName", String.class, null); + String filter = param(params, 2, "filter", String.class, ":3"); + String host = param(params, 3, "host", String.class, "localhost"); + Number port = param(params, 4, "port", Number.class, 4445); + dumpMethod(className, methodName, filter, host, port.intValue()); + } + } + return null; + } + + private static T param(Object[] arr, int index, String name, Class type, T defaultValue) { + Object value = arr.length > index ? arr[index] : null; + if (value == null || (value instanceof String && ((String) value).isEmpty())) { + if (defaultValue == null) { + throw new IllegalArgumentException(name + " must be specified"); + } + value = defaultValue; + } + if (type.isInstance(value)) { + return type.cast(value); + } + throw new IllegalArgumentException("Expecting " + type.getName() + " for " + name + " but was " + value); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java index 6cacaf9a2cf..e12b597453b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java @@ -27,16 +27,15 @@ import java.util.Map; import org.graalvm.compiler.api.runtime.GraalRuntime; import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.DiagnosticsOutputDirectory; -import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.replacements.SnippetCounter.Group; import org.graalvm.compiler.runtime.RuntimeProvider; import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.meta.ResolvedJavaMethod; //JaCoCo Exclude @@ -76,14 +75,6 @@ public interface HotSpotGraalRuntimeProvider extends GraalRuntime, RuntimeProvid */ OptionValues getOptions(); - /** - * Gets the option values associated with this runtime that are applicable for a given method. - * - * @param forMethod the method we are seeking for options for - * @return the options applicable for compiling {@code method} - */ - OptionValues getOptions(ResolvedJavaMethod forMethod); - /** * Determines if the VM is currently bootstrapping the JVMCI compiler. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java index 8d68016b860..34b8ef11282 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.hotspot; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.lir.LIR; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java new file mode 100644 index 00000000000..27d1051a264 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot; + +import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; + +/** + * Determines if a given class is a JVMCI or Graal class for the purpose of + * {@link HotSpotGraalCompilerFactory.Options#CompileGraalWithC1Only}. + */ +public class IsGraalPredicate { + /** + * Module containing {@link HotSpotJVMCICompilerFactory}. + */ + private final Module jvmciModule; + + /** + * Module containing {@link HotSpotGraalCompilerFactory}. + */ + private final Module graalModule; + + /** + * Module containing the {@linkplain CompilerConfigurationFactory#selectFactory selected} + * configuration. + */ + private Module compilerConfigurationModule; + + public IsGraalPredicate() { + jvmciModule = HotSpotJVMCICompilerFactory.class.getModule(); + graalModule = HotSpotGraalCompilerFactory.class.getModule(); + } + + void onCompilerConfigurationFactorySelection(CompilerConfigurationFactory factory) { + compilerConfigurationModule = factory.getClass().getModule(); + } + + boolean apply(Class declaringClass) { + Module module = declaringClass.getModule(); + return jvmciModule == module || graalModule == module || compilerConfigurationModule == module; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java index ca4cb8bced1..b661442652e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java @@ -27,15 +27,19 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; +import java.util.List; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; /** - * An option that encapsulates and configures a print stream. + * An option for a configurable file name that can also open a {@link PrintStream} on the file. If + * no value is given for the option, the stream will output to HotSpot's + * {@link HotSpotJVMCIRuntimeProvider#getLogStream() log} stream */ public class PrintStreamOptionKey extends OptionKey { @@ -44,27 +48,13 @@ public class PrintStreamOptionKey extends OptionKey { } /** - * Replace any instance of %p with an identifying name. Try to get it from the RuntimeMXBean - * name. - * - * @return the name of the file to log to + * @return {@code nameTemplate} with all instances of %p replaced by + * {@link GraalServices#getExecutionID()} and %t by {@link System#currentTimeMillis()} */ - private String getFilename(OptionValues options) { - String name = getValue(options); + private static String makeFilename(String nameTemplate) { + String name = nameTemplate; if (name.contains("%p")) { - try { - String runtimeName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); - int index = runtimeName.indexOf('@'); - if (index != -1) { - long pid = Long.parseLong(runtimeName.substring(0, index)); - runtimeName = Long.toString(pid); - } - name = name.replaceAll("%p", runtimeName); - } catch (NumberFormatException e) { - - } catch (LinkageError err) { - name = String.valueOf(org.graalvm.compiler.debug.PathUtilities.getGlobalTimeStamp()); - } + name = name.replaceAll("%p", GraalServices.getExecutionID()); } if (name.contains("%t")) { name = name.replaceAll("%t", String.valueOf(System.currentTimeMillis())); @@ -118,22 +108,26 @@ public class PrintStreamOptionKey extends OptionKey { * will output to HotSpot's {@link HotSpotJVMCIRuntimeProvider#getLogStream() log} stream. */ public PrintStream getStream(OptionValues options) { - if (getValue(options) != null) { + String nameTemplate = getValue(options); + if (nameTemplate != null) { + String name = makeFilename(nameTemplate); try { final boolean enableAutoflush = true; - PrintStream ps = new PrintStream(new FileOutputStream(getFilename(options)), enableAutoflush); + PrintStream ps = new PrintStream(new FileOutputStream(name), enableAutoflush); /* * Add the JVM and Java arguments to the log file to help identity it. */ - String inputArguments = String.join(" ", java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments()); - ps.println("VM Arguments: " + inputArguments); + List inputArguments = GraalServices.getInputArguments(); + if (inputArguments != null) { + ps.println("VM Arguments: " + String.join(" ", inputArguments)); + } String cmd = System.getProperty("sun.java.command"); if (cmd != null) { ps.println("sun.java.command=" + cmd); } return ps; } catch (FileNotFoundException e) { - throw new RuntimeException("couldn't open file: " + getValue(options), e); + throw new RuntimeException("couldn't open file: " + name, e); } } else { return new PrintStream(new DelayedOutputStream()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/WeakClassLoaderSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/WeakClassLoaderSet.java new file mode 100644 index 00000000000..5192504f63c --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/WeakClassLoaderSet.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 org.graalvm.compiler.hotspot; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; + +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; + +/** + * A set of weak references to {@link ClassLoader}s. + */ +public final class WeakClassLoaderSet { + + /** + * Copy-on-write set of loaders. + */ + private volatile AtomicReference>> loaders = new AtomicReference<>(EconomicSet.create(RefEquivalence.INSTANCE)); + + public WeakClassLoaderSet(ClassLoader... initialEntries) { + for (ClassLoader loader : initialEntries) { + loaders.get().add(new WeakReference<>(loader)); + } + } + + /** + * Adds {@code loader} to this set. + */ + public void add(ClassLoader loader) { + Reference addNewRef = new WeakReference<>(loader); + EconomicSet> currentLoaders = loaders.get(); + if (!currentLoaders.contains(addNewRef)) { + this.loaders.getAndUpdate(new UnaryOperator>>() { + @Override + public EconomicSet> apply(EconomicSet> t) { + EconomicSet> newLoaders = EconomicSet.create(RefEquivalence.INSTANCE, t); + newLoaders.add(addNewRef); + return newLoaders; + } + }); + } + } + + /** + * Tries to resolve {@code className} to {@link Class} instances with the loaders in this set. + * + * @param className name of a class to resolve + * @param resolutionFailures all resolution failures are returned in this set + * @return the set of classes successfully resolved + */ + public EconomicSet> resolve(String className, EconomicSet resolutionFailures) { + EconomicSet> found = EconomicSet.create(); + Iterator> it = loaders.get().iterator(); + while (it.hasNext()) { + Reference ref = it.next(); + ClassLoader loader = ref.get(); + if (loader == null) { + it.remove(); + continue; + } + try { + Class clazz = Class.forName(className, false, loader); + found.add(clazz); + } catch (ClassNotFoundException ex) { + resolutionFailures.add(ex); + } + } + return found; + } + + private static final class RefEquivalence extends Equivalence { + static final Equivalence INSTANCE = new RefEquivalence(); + + private RefEquivalence() { + } + + @Override + public boolean equals(Object a, Object b) { + Reference refA = (Reference) a; + Reference refB = (Reference) b; + Object referentA = refA.get(); + Object referentB = refB.get(); + return Objects.equals(referentA, referentB); + } + + @Override + public int hashCode(Object o) { + Reference ref = (Reference) o; + Object obj = ref.get(); + return obj == null ? 0 : obj.hashCode(); + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/AddressLoweringHotSpotSuitesProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/AddressLoweringHotSpotSuitesProvider.java index 7ffe6632298..48e677a77da 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/AddressLoweringHotSpotSuitesProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/AddressLoweringHotSpotSuitesProvider.java @@ -29,7 +29,7 @@ import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.common.AddressLoweringPhase; +import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.common.ExpandLogicPhase; import org.graalvm.compiler.phases.common.FixReadsPhase; import org.graalvm.compiler.phases.tiers.LowTierContext; @@ -41,10 +41,10 @@ import org.graalvm.compiler.phases.tiers.SuitesCreator; */ public class AddressLoweringHotSpotSuitesProvider extends HotSpotSuitesProvider { - private final AddressLoweringPhase.AddressLowering addressLowering; + private final Phase addressLowering; public AddressLoweringHotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, - AddressLoweringPhase.AddressLowering addressLowering) { + Phase addressLowering) { super(defaultSuitesCreator, config, runtime); this.addressLowering = addressLowering; } @@ -57,7 +57,7 @@ public class AddressLoweringHotSpotSuitesProvider extends HotSpotSuitesProvider if (findPhase == null) { findPhase = suites.getLowTier().findPhase(ExpandLogicPhase.class); } - findPhase.add(new AddressLoweringPhase(addressLowering)); + findPhase.add(addressLowering); return suites; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 395521ad0fd..e493d920852 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -36,7 +36,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil. import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_LAYOUT_HELPER_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.lang.ref.Reference; @@ -155,7 +155,7 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.replacements.DefaultJavaLoweringProvider; import org.graalvm.compiler.replacements.nodes.AssertionNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.HotSpotCallingConventionType; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java index 3417f71f994..286ddfd1f47 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java @@ -30,7 +30,7 @@ import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition. import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; @@ -43,7 +43,7 @@ import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.CodeCacheProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index cdf8b8f8e5e..cbd33f08495 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -26,7 +26,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION; import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MutableCallSite; @@ -100,10 +100,9 @@ import org.graalvm.compiler.replacements.NodeIntrinsificationProvider; import org.graalvm.compiler.replacements.ReplacementsImpl; import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins; import org.graalvm.compiler.serviceprovider.GraalServices; -import org.graalvm.compiler.serviceprovider.JDK9Method; import org.graalvm.compiler.word.WordOperationPlugin; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -160,7 +159,7 @@ public class HotSpotGraphBuilderPlugins { @Override public void run() { BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider(); - registerObjectPlugins(invocationPlugins, options, replacementBytecodeProvider); + registerObjectPlugins(invocationPlugins, options, config, replacementBytecodeProvider); registerClassPlugins(plugins, config, replacementBytecodeProvider); registerSystemPlugins(invocationPlugins, foreignCalls); registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider); @@ -186,7 +185,7 @@ public class HotSpotGraphBuilderPlugins { return plugins; } - private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, BytecodeProvider bytecodeProvider) { + private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { Registration r = new Registration(plugins, Object.class, bytecodeProvider); if (!GeneratePIC.getValue(options)) { // FIXME: clone() requires speculation and requires a fix in here (to check that @@ -210,6 +209,12 @@ public class HotSpotGraphBuilderPlugins { }); } r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class); + if (config.inlineNotify()) { + r.registerMethodSubstitution(ObjectSubstitutions.class, "notify", Receiver.class); + } + if (config.inlineNotifyAll()) { + r.registerMethodSubstitution(ObjectSubstitutions.class, "notifyAll", Receiver.class); + } } private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { @@ -440,7 +445,7 @@ public class HotSpotGraphBuilderPlugins { public static final String constantPoolClass; static { - if (JDK9Method.Java8OrEarlier) { + if (Java8OrEarlier) { cbcEncryptName = "encrypt"; cbcDecryptName = "decrypt"; aesEncryptName = "encryptBlock"; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index c69c6f2c84f..87d1f595c93 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -97,11 +97,11 @@ import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.Una import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.util.EnumMap; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.debug.GraalError; @@ -124,7 +124,7 @@ import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; @@ -140,6 +140,9 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall public static final ForeignCallDescriptor JAVA_TIME_MILLIS = new ForeignCallDescriptor("javaTimeMillis", long.class); public static final ForeignCallDescriptor JAVA_TIME_NANOS = new ForeignCallDescriptor("javaTimeNanos", long.class); + public static final ForeignCallDescriptor NOTIFY = new ForeignCallDescriptor("object_notify", boolean.class, Object.class); + public static final ForeignCallDescriptor NOTIFY_ALL = new ForeignCallDescriptor("object_notifyAll", boolean.class, Object.class); + public HotSpotHostForeignCallsProvider(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes) { super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); @@ -292,6 +295,8 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall linkForeignCall(options, providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any()); linkForeignCall(options, providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, NOT_REEXECUTABLE, any()); linkForeignCall(options, providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(options, providers, NOTIFY, c.notifyAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any()); + linkForeignCall(options, providers, NOTIFY_ALL, c.notifyAllAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any()); linkForeignCall(options, providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE); linkForeignCall(options, providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE); linkForeignCall(options, providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java index 5d7aaa2bfd3..36e04c5e9c4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java @@ -22,15 +22,9 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; - -import java.lang.invoke.MethodHandle; import java.lang.reflect.Type; -import java.util.Set; -import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.GraalOptions; -import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; @@ -43,7 +37,6 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.replacements.nodes.MacroNode; -import org.graalvm.compiler.serviceprovider.JDK9Method; import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; import jdk.vm.ci.meta.JavaKind; @@ -54,18 +47,11 @@ import jdk.vm.ci.meta.ResolvedJavaType; */ final class HotSpotInvocationPlugins extends InvocationPlugins { private final GraalHotSpotVMConfig config; - private final EconomicSet trustedModules; - private final ClassLoader extLoader; + private final IntrinsificationPredicate intrinsificationPredicate; HotSpotInvocationPlugins(GraalHotSpotVMConfig config, CompilerConfiguration compilerConfiguration) { this.config = config; - if (Java8OrEarlier) { - extLoader = getExtLoader(); - trustedModules = null; - } else { - extLoader = null; - trustedModules = initTrustedModules(compilerConfiguration); - } + intrinsificationPredicate = new IntrinsificationPredicate(compilerConfiguration); } @Override @@ -114,79 +100,12 @@ final class HotSpotInvocationPlugins extends InvocationPlugins { return type != null && "Ljava/lang/Class;".equals(type.getName()); } - /** - * {@inheritDoc} - * - * On JDK 8, only classes loaded by the boot, JVMCI or extension class loaders are trusted. - * - * On JDK 9 and later, only classes in the {@link CompilerConfiguration} defining module or any - * of its module dependencies are trusted. - */ @Override public boolean canBeIntrinsified(ResolvedJavaType declaringClass) { if (declaringClass instanceof HotSpotResolvedJavaType) { - Class javaClass = ((HotSpotResolvedJavaType) declaringClass).mirror(); - if (Java8OrEarlier) { - ClassLoader cl = javaClass.getClassLoader(); - return cl == null || cl == getClass().getClassLoader() || cl == extLoader; - } else { - Object module = JDK9Method.getModule(javaClass); - return trustedModules.contains(module); - } + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) declaringClass; + return intrinsificationPredicate.apply(type.mirror()); } return false; } - - private static ClassLoader getExtLoader() { - try { - Object launcher = Class.forName("sun.misc.Launcher").getMethod("getLauncher").invoke(null); - ClassLoader appLoader = (ClassLoader) launcher.getClass().getMethod("getClassLoader").invoke(launcher); - ClassLoader extLoader = appLoader.getParent(); - assert extLoader.getClass().getName().equals("sun.misc.Launcher$ExtClassLoader") : extLoader; - return extLoader; - } catch (Exception e) { - throw new GraalError(e); - } - } - - /** - * Gets the set of modules whose methods can be intrinsified. This set is the module owning the - * class of {@code compilerConfiguration} and all its dependencies. - */ - private static EconomicSet initTrustedModules(CompilerConfiguration compilerConfiguration) throws GraalError { - try { - EconomicSet res = EconomicSet.create(); - Object compilerConfigurationModule = JDK9Method.getModule(compilerConfiguration.getClass()); - res.add(compilerConfigurationModule); - Class moduleClass = compilerConfigurationModule.getClass(); - Object layer = JDK9Method.lookupMethodHandle(moduleClass, "getLayer").invoke(compilerConfigurationModule); - Class layerClass = layer.getClass(); - MethodHandle getName = JDK9Method.lookupMethodHandle(moduleClass, "getName"); - Set modules = (Set) JDK9Method.lookupMethodHandle(layerClass, "modules").invoke(layer); - Object descriptor = JDK9Method.lookupMethodHandle(moduleClass, "getDescriptor").invoke(compilerConfigurationModule); - Class moduleDescriptorClass = descriptor.getClass(); - Set requires = (Set) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "requires").invoke(descriptor); - boolean isAutomatic = (Boolean) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "isAutomatic").invoke(descriptor); - if (isAutomatic) { - throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module", - getName.invoke(compilerConfigurationModule), compilerConfiguration.getClass().getName())); - } - MethodHandle requireNameGetter = null; - for (Object require : requires) { - if (requireNameGetter == null) { - requireNameGetter = JDK9Method.lookupMethodHandle(require.getClass(), "name"); - } - String name = (String) requireNameGetter.invoke(require); - for (Object module : modules) { - String moduleName = (String) getName.invoke(module); - if (moduleName.equals(name)) { - res.add(module); - } - } - } - return res; - } catch (Throwable e) { - throw new GraalError(e); - } - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java index d2d709e7436..b4da804a3b2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java @@ -22,14 +22,14 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordFactory; @ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"}) public class HotSpotUnsafeSubstitutions { @@ -41,7 +41,7 @@ public class HotSpotUnsafeSubstitutions { static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) { Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset)); Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset)); - Word size = Word.signed(bytes); + Word size = WordFactory.signed(bytes); HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java index 246491cef7d..0b6c70eb25c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.hotspot.meta; import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ; import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE; import static org.graalvm.compiler.nodes.ConstantNode.forBoolean; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.BridgeMethodUtils; @@ -53,7 +53,7 @@ import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.word.WordOperationPlugin; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/IntrinsificationPredicate.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/IntrinsificationPredicate.java new file mode 100644 index 00000000000..9f04b12dc9e --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/IntrinsificationPredicate.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.meta; + +import java.lang.module.ModuleDescriptor.Requires; + +import jdk.internal.vm.compiler.collections.EconomicSet; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; + +/** + * Determines if methods in a given class can be intrinsified. + * + * Only classes loaded from the module defining the compiler configuration or any of its transitive + * dependencies can be intrinsified. + * + * This version of the class must be used on JDK 9 or later. + */ +public final class IntrinsificationPredicate { + /** + * Set of modules composed of the module defining the compiler configuration and its transitive + * dependencies. + */ + private final EconomicSet trustedModules; + + IntrinsificationPredicate(CompilerConfiguration compilerConfiguration) { + trustedModules = EconomicSet.create(); + Module compilerConfigurationModule = compilerConfiguration.getClass().getModule(); + if (compilerConfigurationModule.getDescriptor().isAutomatic()) { + throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module", + compilerConfigurationModule.getName(), compilerConfiguration.getClass().getName())); + } + trustedModules.add(compilerConfigurationModule); + for (Requires require : compilerConfigurationModule.getDescriptor().requires()) { + for (Module module : compilerConfigurationModule.getLayer().modules()) { + if (module.getName().equals(require.name())) { + trustedModules.add(module); + } + } + } + } + + public boolean apply(Class declaringClass) { + Module module = declaringClass.getModule(); + return trustedModules.contains(module); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java index 63657a69d24..c76a5fc12dd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java @@ -38,7 +38,7 @@ import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java index 0c12d547d83..899c94be9ed 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Intrinsic for closing a {@linkplain BeginLockScopeNode scope} binding a stack-based lock with an diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java index a7e28a9dcb6..146cc6dac6b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java @@ -42,7 +42,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java index 63674b901da..0bc44cd92b8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; @NodeInfo(cycles = CYCLES_4, size = SIZE_16, allowedUsageTypes = {Memory}) public class InitializeKlassNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java index b7af9ab772a..73568842053 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java @@ -43,7 +43,7 @@ import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.meta.Constant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java index f8a8f92e9e6..4f9e437a30a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.hotspot.nodes.aot; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.InputType; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java index f811e3d923f..3da7861061c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java @@ -43,7 +43,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java index e790daea4fd..446f9bca5bf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java @@ -25,15 +25,12 @@ package org.graalvm.compiler.hotspot.phases; import static jdk.vm.ci.meta.SpeculationLog.SpeculationReason; import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.CounterKey; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -74,6 +71,10 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.runtime.JVMCICompiler; public class OnStackReplacementPhase extends Phase { @@ -97,6 +98,7 @@ public class OnStackReplacementPhase extends Phase { } @Override + @SuppressWarnings("try") protected void run(StructuredGraph graph) { DebugContext debug = graph.getDebug(); if (graph.getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI) { @@ -158,64 +160,67 @@ public class OnStackReplacementPhase extends Phase { debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement loop peeling result"); } while (true); - FrameState osrState = osr.stateAfter(); - osr.setStateAfter(null); - OSRStartNode osrStart = graph.add(new OSRStartNode()); StartNode start = graph.start(); - FixedNode next = osr.next(); - osr.setNext(null); - osrStart.setNext(next); - graph.setStart(osrStart); - osrStart.setStateAfter(osrState); + FrameState osrState = osr.stateAfter(); + OSRStartNode osrStart; + try (DebugCloseable context = osr.withNodeSourcePosition()) { + osr.setStateAfter(null); + osrStart = graph.add(new OSRStartNode()); + FixedNode next = osr.next(); + osr.setNext(null); + osrStart.setNext(next); + graph.setStart(osrStart); + osrStart.setStateAfter(osrState); - debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start"); - final int localsSize = osrState.localsSize(); - final int locksSize = osrState.locksSize(); + debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start"); + final int localsSize = osrState.localsSize(); + final int locksSize = osrState.locksSize(); - for (int i = 0; i < localsSize + locksSize; i++) { - ValueNode value = null; - if (i >= localsSize) { - value = osrState.lockAt(i - localsSize); - } else { - value = osrState.localAt(i); - } - if (value instanceof EntryProxyNode) { - EntryProxyNode proxy = (EntryProxyNode) value; - /* - * We need to drop the stamp since the types we see during OSR may be too precise - * (if a branch was not parsed for example). In cases when this is possible, we - * insert a guard and narrow the OSRLocal stamp at its usages. - */ - Stamp narrowedStamp = proxy.value().stamp(NodeView.DEFAULT); - Stamp unrestrictedStamp = proxy.stamp(NodeView.DEFAULT).unrestricted(); - ValueNode osrLocal; + for (int i = 0; i < localsSize + locksSize; i++) { + ValueNode value = null; if (i >= localsSize) { - osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, unrestrictedStamp)); + value = osrState.lockAt(i - localsSize); } else { - osrLocal = graph.addOrUnique(new OSRLocalNode(i, unrestrictedStamp)); + value = osrState.localAt(i); } - // Speculate on the OSRLocal stamps that could be more precise. - OSRLocalSpeculationReason reason = new OSRLocalSpeculationReason(osrState.bci, narrowedStamp, i); - if (graph.getSpeculationLog().maySpeculate(reason) && osrLocal instanceof OSRLocalNode && value.getStackKind().equals(JavaKind.Object) && !narrowedStamp.isUnrestricted()) { - // Add guard. - LogicNode check = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) narrowedStamp, osrLocal, null, null)); - JavaConstant constant = graph.getSpeculationLog().speculate(reason); - FixedGuardNode guard = graph.add(new FixedGuardNode(check, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, constant, false)); - graph.addAfterFixed(osrStart, guard); + if (value instanceof EntryProxyNode) { + EntryProxyNode proxy = (EntryProxyNode) value; + /* + * We need to drop the stamp since the types we see during OSR may be too + * precise (if a branch was not parsed for example). In cases when this is + * possible, we insert a guard and narrow the OSRLocal stamp at its usages. + */ + Stamp narrowedStamp = proxy.value().stamp(NodeView.DEFAULT); + Stamp unrestrictedStamp = proxy.stamp(NodeView.DEFAULT).unrestricted(); + ValueNode osrLocal; + if (i >= localsSize) { + osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, unrestrictedStamp)); + } else { + osrLocal = graph.addOrUnique(new OSRLocalNode(i, unrestrictedStamp)); + } + // Speculate on the OSRLocal stamps that could be more precise. + OSRLocalSpeculationReason reason = new OSRLocalSpeculationReason(osrState.bci, narrowedStamp, i); + if (graph.getSpeculationLog().maySpeculate(reason) && osrLocal instanceof OSRLocalNode && value.getStackKind().equals(JavaKind.Object) && !narrowedStamp.isUnrestricted()) { + // Add guard. + LogicNode check = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) narrowedStamp, osrLocal, null, null)); + JavaConstant constant = graph.getSpeculationLog().speculate(reason); + FixedGuardNode guard = graph.add(new FixedGuardNode(check, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, constant, false)); + graph.addAfterFixed(osrStart, guard); - // Replace with a more specific type at usages. - // We know that we are at the root, - // so we need to replace the proxy in the state. - proxy.replaceAtMatchingUsages(osrLocal, n -> n == osrState); - osrLocal = graph.addOrUnique(new PiNode(osrLocal, narrowedStamp, guard)); + // Replace with a more specific type at usages. + // We know that we are at the root, + // so we need to replace the proxy in the state. + proxy.replaceAtMatchingUsages(osrLocal, n -> n == osrState); + osrLocal = graph.addOrUnique(new PiNode(osrLocal, narrowedStamp, guard)); + } + proxy.replaceAndDelete(osrLocal); + } else { + assert value == null || value instanceof OSRLocalNode; } - proxy.replaceAndDelete(osrLocal); - } else { - assert value == null || value instanceof OSRLocalNode; } - } - osr.replaceAtUsages(InputType.Guard, osrStart); + osr.replaceAtUsages(InputType.Guard, osrStart); + } debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies"); GraphUtil.killCFG(start); debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement result"); @@ -223,21 +228,24 @@ public class OnStackReplacementPhase extends Phase { if (currentOSRWithLocks) { OsrWithLocksCount.increment(debug); - for (int i = osrState.monitorIdCount() - 1; i >= 0; --i) { - MonitorIdNode id = osrState.monitorIdAt(i); - ValueNode lockedObject = osrState.lockAt(i); - OSRMonitorEnterNode osrMonitorEnter = graph.add(new OSRMonitorEnterNode(lockedObject, id)); - for (Node usage : id.usages()) { - if (usage instanceof AccessMonitorNode) { - AccessMonitorNode access = (AccessMonitorNode) usage; - access.setObject(lockedObject); + try (DebugCloseable context = osrStart.withNodeSourcePosition()) { + for (int i = osrState.monitorIdCount() - 1; i >= 0; --i) { + MonitorIdNode id = osrState.monitorIdAt(i); + ValueNode lockedObject = osrState.lockAt(i); + OSRMonitorEnterNode osrMonitorEnter = graph.add(new OSRMonitorEnterNode(lockedObject, id)); + for (Node usage : id.usages()) { + if (usage instanceof AccessMonitorNode) { + AccessMonitorNode access = (AccessMonitorNode) usage; + access.setObject(lockedObject); + } } + FixedNode oldNext = osrStart.next(); + oldNext.replaceAtPredecessor(null); + osrMonitorEnter.setNext(oldNext); + osrStart.setNext(osrMonitorEnter); } - FixedNode oldNext = osrStart.next(); - oldNext.replaceAtPredecessor(null); - osrMonitorEnter.setNext(oldNext); - osrStart.setNext(osrMonitorEnter); } + debug.dump(DebugContext.DETAILED_LEVEL, graph, "After inserting OSR monitor enters"); /* * Ensure balanced monitorenter - monitorexit diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java index 4c7d5cce096..1173734b9c4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.hotspot.phases; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; @@ -53,22 +54,25 @@ public class WriteBarrierAdditionPhase extends Phase { this.config = config; } + @SuppressWarnings("try") @Override protected void run(StructuredGraph graph) { for (Node n : graph.getNodes()) { - if (n instanceof ReadNode) { - addReadNodeBarriers((ReadNode) n, graph); - } else if (n instanceof WriteNode) { - addWriteNodeBarriers((WriteNode) n, graph); - } else if (n instanceof LoweredAtomicReadAndWriteNode) { - LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n; - addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph); - } else if (n instanceof AbstractCompareAndSwapNode) { - addCASBarriers((AbstractCompareAndSwapNode) n, graph); - } else if (n instanceof ArrayRangeWrite) { - ArrayRangeWrite node = (ArrayRangeWrite) n; - if (node.writesObjectArray()) { - addArrayRangeBarriers(node, graph); + try (DebugCloseable scope = n.graph().withNodeSourcePosition(n)) { + if (n instanceof ReadNode) { + addReadNodeBarriers((ReadNode) n, graph); + } else if (n instanceof WriteNode) { + addWriteNodeBarriers((WriteNode) n, graph); + } else if (n instanceof LoweredAtomicReadAndWriteNode) { + LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n; + addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph); + } else if (n instanceof AbstractCompareAndSwapNode) { + addCASBarriers((AbstractCompareAndSwapNode) n, graph); + } else if (n instanceof ArrayRangeWrite) { + ArrayRangeWrite node = (ArrayRangeWrite) n; + if (node.writesObjectArray()) { + addArrayRangeBarriers(node, graph); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java index a918c30948d..b0118e62f21 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java @@ -27,6 +27,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize; import java.util.Map; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.Option; @@ -36,6 +37,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.common.inlining.info.InlineInfo; import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy; +import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy; import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; @@ -61,13 +63,14 @@ public class AOTInliningPolicy extends GreedyInliningPolicy { } @Override - public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + public Decision isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + final boolean isTracing = GraalOptions.TraceInlining.getValue(replacements.getOptions()); final InlineInfo info = invocation.callee(); for (int i = 0; i < info.numberOfMethods(); ++i) { HotSpotResolvedObjectType t = (HotSpotResolvedObjectType) info.methodAt(i).getDeclaringClass(); if (t.getFingerprint() == 0) { - return false; + return InliningPolicy.Decision.NO; } } @@ -77,17 +80,17 @@ public class AOTInliningPolicy extends GreedyInliningPolicy { OptionValues options = info.graph().getOptions(); if (InlineEverything.getValue(options)) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "inline everything"); } if (isIntrinsic(replacements, info)) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "intrinsic"); } if (info.shouldInline()) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "forced inlining"); } double inliningBonus = getInliningBonus(info); @@ -95,17 +98,18 @@ public class AOTInliningPolicy extends GreedyInliningPolicy { if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); } double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus)); if (nodes <= maximumNodes) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, nodes, maximumNodes); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, + nodes, maximumNodes); } InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); - return false; + return InliningPolicy.Decision.NO.withReason(isTracing, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java index dd798786991..f0f92a975de 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java @@ -32,7 +32,7 @@ import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ResolvedJavaType; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java index ba682ccf2e1..c2a2f64985f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java @@ -29,7 +29,7 @@ import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; import java.util.HashSet; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java index e525e6c7942..0e8a2ee2801 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java @@ -41,9 +41,9 @@ import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32CSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32CSubstitutions.java index 3c872a724c8..b80f12478a2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32CSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32CSubstitutions.java @@ -32,8 +32,8 @@ import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordBase; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordBase; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java index 8c8345e54aa..4919678310d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java @@ -38,9 +38,9 @@ import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordBase; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordBase; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java index 7e6d2960d70..89e25aab441 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java @@ -40,9 +40,9 @@ import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java index ca36e1678f3..d48c6b56559 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java @@ -48,7 +48,7 @@ import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java index a0d09fa130a..bd2207aba12 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java @@ -47,7 +47,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.TargetDescription; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index 4f27b0aa7a1..250bfa0fa2e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -59,8 +59,8 @@ import org.graalvm.compiler.replacements.ReplacementsUtil; import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; import org.graalvm.compiler.replacements.nodes.WriteRegisterNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.Register; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java index 66971954ac3..bc713220da3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java @@ -40,7 +40,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.JavaConstant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java index 585f4d33553..4abddcfc450 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java @@ -51,7 +51,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.Register; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java index 75509efba5d..9e9c4ad05f5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java @@ -120,10 +120,10 @@ import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordBase; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordBase; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.Register; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java index 467f8f98aee..7f3528a6264 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java @@ -117,8 +117,8 @@ import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.MemoryBarriers; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java index 1ca911e89a7..67895a6f87b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectSubstitutions.java @@ -24,6 +24,11 @@ package org.graalvm.compiler.hotspot.replacements; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; // JaCoCo Exclude @@ -37,4 +42,21 @@ public class ObjectSubstitutions { public static int hashCode(final Object thisObj) { return IdentityHashCodeNode.identityHashCode(thisObj); } + + @MethodSubstitution(isStatic = false) + public static void notify(final Object thisObj) { + if (!fastNotifyStub(HotSpotHostForeignCallsProvider.NOTIFY, thisObj)) { + notify(thisObj); + } + } + + @MethodSubstitution(isStatic = false) + public static void notifyAll(final Object thisObj) { + if (!fastNotifyStub(HotSpotHostForeignCallsProvider.NOTIFY_ALL, thisObj)) { + notifyAll(thisObj); + } + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native boolean fastNotifyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object o); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java index 43eedc6669b..d23ca0ddd6e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java @@ -23,7 +23,7 @@ package org.graalvm.compiler.hotspot.replacements; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitution; @@ -33,8 +33,8 @@ import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java index 95ecd5b55d7..661abbdfeee 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java @@ -23,7 +23,7 @@ package org.graalvm.compiler.hotspot.replacements; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitution; @@ -33,8 +33,8 @@ import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java index 18d101fb16c..f491731eaf9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java @@ -23,7 +23,7 @@ package org.graalvm.compiler.hotspot.replacements; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitution; @@ -33,8 +33,8 @@ import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java index d5131e802e3..6b925d22154 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java @@ -42,7 +42,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.replacements.nodes.CStringConstant; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java index bb720f1629e..4a85bf14d86 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java @@ -28,7 +28,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil. import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadInterruptedOffset; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.osThreadOffset; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.threadObjectOffset; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitution; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java index 5682da564a6..ab972c66e32 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java @@ -87,10 +87,10 @@ import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.replacements.nodes.DirectStoreNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.UnsignedWord; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.TargetDescription; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java index 863db348004..1be6487ed2d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java @@ -58,7 +58,7 @@ import org.graalvm.compiler.nodes.memory.MemoryNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.JavaConstant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java index 61170a8427c..3e2e3e35247 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.hotspot.replacements.arraycopy; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -31,7 +31,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java index 72e435ed235..511da081c63 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java @@ -40,7 +40,7 @@ import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probabil import java.lang.reflect.Method; import java.util.EnumMap; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Snippet; @@ -77,8 +77,8 @@ import org.graalvm.compiler.replacements.Snippets; import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.DeoptimizationAction; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java index e6fb867a83e..2d1ceaee1f1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java @@ -52,7 +52,7 @@ import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.word.Word; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java index 70373bfe4e1..80736abaf0b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java @@ -42,7 +42,7 @@ import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java index ee73126f170..ea1ea1eed09 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java @@ -28,7 +28,7 @@ import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition. import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.REEXECUTABLE; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java index 58077ba3900..061b52138c1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java @@ -51,7 +51,7 @@ import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.Register; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java index e41bc188819..f611bbfa7f9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java @@ -34,11 +34,9 @@ import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; -import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.JavaMethodContext; -import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; @@ -57,7 +55,7 @@ import org.graalvm.compiler.replacements.GraphKit; import org.graalvm.compiler.replacements.nodes.ReadRegisterNode; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; import jdk.vm.ci.hotspot.HotSpotSignature; @@ -232,33 +230,30 @@ public class ForeignCallStub extends Stub { WordTypes wordTypes = providers.getWordTypes(); Class[] args = linkage.getDescriptor().getArgumentTypes(); boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn()); - StructuredGraph graph = new StructuredGraph.Builder(options, debug).name(toString()).compilationId(compilationId).build(); - graph.disableUnsafeAccessTracking(); - graph.setTrackNodeSourcePosition(); + try { ResolvedJavaMethod thisMethod = providers.getMetaAccess().lookupJavaMethod(ForeignCallStub.class.getDeclaredMethod("getGraph", DebugContext.class, CompilationIdentifier.class)); - try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(thisMethod))) { - GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); - ParameterNode[] params = createParameters(kit, args); - ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); - ValueNode result = createTargetCall(kit, params, thread); - kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); - if (isObjectResult) { - InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); - result = kit.createInvoke(StubUtil.class, "verifyObject", object); - } - kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); - debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph"); - - kit.inlineInvokes(); - new RemoveValueProxyPhase().apply(graph); - - debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation"); + GraphKit kit = new GraphKit(debug, thisMethod, providers, wordTypes, providers.getGraphBuilderPlugins(), compilationId, toString()); + StructuredGraph graph = kit.getGraph(); + ParameterNode[] params = createParameters(kit, args); + ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); + ValueNode result = createTargetCall(kit, params, thread); + kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); + if (isObjectResult) { + InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); + result = kit.createInvoke(StubUtil.class, "verifyObject", object); } + kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); + debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph"); + + kit.inlineInvokes("Foreign call stub.", "Backend"); + new RemoveValueProxyPhase().apply(graph); + + debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation"); + return graph; } catch (Exception e) { throw GraalError.shouldNotReachHere(e); } - return graph; } private ParameterNode[] createParameters(GraphKit kit, Class[] args) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java index fc1d26262ba..627c744bc5f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java @@ -59,7 +59,7 @@ import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.Register; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java index 9ebcee8bce7..b0199d71cfa 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java @@ -81,7 +81,7 @@ import org.graalvm.compiler.hotspot.word.KlassPointer; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.code.Register; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java index a5d4f5bd8af..f4e3c23b10b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java @@ -48,9 +48,10 @@ import jdk.vm.ci.meta.DefaultProfilingInfo; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.TriState; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Description; @@ -137,7 +138,7 @@ public abstract class Stub { */ public Stub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { this.linkage = linkage; - this.options = options; + this.options = new OptionValues(options, GraalOptions.TraceInlining, GraalOptions.TraceInliningForStubsAndSnippets.getValue(options)); this.providers = providers; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java index 725bb138bf5..0a0856bf337 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java @@ -50,8 +50,8 @@ import org.graalvm.compiler.nodes.SnippetAnchorNode; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.replacements.Log; import org.graalvm.compiler.word.Word; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.DeoptimizationAction; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java index a3c34070a2c..a7eaf09d4e5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java @@ -47,7 +47,7 @@ import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; import org.graalvm.compiler.nodes.UnwindNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; -import org.graalvm.word.Pointer; +import jdk.internal.vm.compiler.word.Pointer; import jdk.vm.ci.code.Register; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java index 7efa5fa81de..a4fc8188beb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java @@ -29,8 +29,8 @@ import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.T import org.graalvm.compiler.word.Word.Opcode; import org.graalvm.compiler.word.Word.Operation; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; /** * Marker type for a metaspace pointer to a type. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java index 22a64302a89..48462696cea 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java @@ -29,11 +29,11 @@ import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.Word.Opcode; import org.graalvm.compiler.word.Word.Operation; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.SignedWord; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordBase; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.SignedWord; +import jdk.internal.vm.compiler.word.UnsignedWord; +import jdk.internal.vm.compiler.word.WordBase; /** * Marker type for a metaspace pointer. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java index be27d05d013..0ff4010e150 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java @@ -26,7 +26,7 @@ import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.P import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE; import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_METHOD_POINTER; -import org.graalvm.word.Pointer; +import jdk.internal.vm.compiler.word.Pointer; /** * Marker type for a metaspace pointer to a method. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java index 755b5c942b3..c3f5c13b2c0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java @@ -38,6 +38,7 @@ import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD; import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE; import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN; import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD; +import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC; import static org.graalvm.compiler.bytecode.Bytecodes.GOTO; import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W; import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD; @@ -71,6 +72,7 @@ import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE; import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH; import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN; import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD; +import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC; import static org.graalvm.compiler.bytecode.Bytecodes.RET; import static org.graalvm.compiler.bytecode.Bytecodes.RETURN; import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD; @@ -81,13 +83,12 @@ import static org.graalvm.compiler.core.common.GraalOptions.SupportJsrBytecodes; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.TreeSet; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; import org.graalvm.compiler.bytecode.BytecodeStream; @@ -142,20 +143,20 @@ public final class BciBlockMapping { public static class BciBlock implements Cloneable { - protected int id; - public int startBci; - public int endBci; - public boolean isExceptionEntry; - public boolean isLoopHeader; - public int loopId; - public int loopEnd; - protected List successors; + int id; + final int startBci; + int endBci; + private boolean isExceptionEntry; + private boolean isLoopHeader; + int loopId; + int loopEnd; + List successors; private int predecessorCount; private boolean visited; private boolean active; - public long loops; - public JSRData jsrData; + long loops; + JSRData jsrData; public static class JSRData implements Cloneable { public EconomicMap jsrAlternatives; @@ -174,8 +175,21 @@ public final class BciBlockMapping { } } - public BciBlock() { - this.successors = new ArrayList<>(4); + BciBlock(int startBci) { + this.startBci = startBci; + this.successors = new ArrayList<>(); + } + + public int getStartBci() { + return startBci; + } + + public int getEndBci() { + return endBci; + } + + public long getLoops() { + return loops; } public BciBlock exceptionDispatchBlock() { @@ -216,14 +230,16 @@ public final class BciBlockMapping { @Override public String toString() { StringBuilder sb = new StringBuilder("B").append(getId()); - sb.append('[').append(startBci).append("->").append(endBci); - if (isLoopHeader || isExceptionEntry) { + sb.append('[').append(startBci).append("..").append(endBci); + if (isLoopHeader || isExceptionEntry || this instanceof ExceptionDispatchBlock) { sb.append(' '); if (isLoopHeader) { sb.append('L'); } if (isExceptionEntry) { sb.append('!'); + } else if (this instanceof ExceptionDispatchBlock) { + sb.append(""); } } sb.append(']'); @@ -412,11 +428,40 @@ public final class BciBlockMapping { } successors.clear(); } + + public boolean isExceptionDispatch() { + return false; + } } public static class ExceptionDispatchBlock extends BciBlock { - public ExceptionHandler handler; - public int deoptBci; + public final ExceptionHandler handler; + public final int deoptBci; + + /** + * Constructor for a normal dispatcher. + */ + ExceptionDispatchBlock(ExceptionHandler handler, int deoptBci) { + super(handler.getHandlerBCI()); + this.endBci = startBci; + this.deoptBci = deoptBci; + this.handler = handler; + } + + /** + * Constructor for the method unwind dispatcher. + */ + ExceptionDispatchBlock(int deoptBci) { + super(deoptBci); + this.endBci = deoptBci; + this.deoptBci = deoptBci; + this.handler = null; + } + + @Override + public boolean isExceptionDispatch() { + return true; + } } /** @@ -480,7 +525,6 @@ public final class BciBlockMapping { private boolean verify() { for (BciBlock block : blocks) { assert blocks[block.getId()] == block; - for (int i = 0; i < block.getSuccessorCount(); i++) { BciBlock sux = block.getSuccessor(i); if (sux instanceof ExceptionDispatchBlock) { @@ -623,6 +667,8 @@ public final class BciBlockMapping { case CALOAD: case SALOAD: case ARRAYLENGTH: + case PUTSTATIC: + case GETSTATIC: case PUTFIELD: case GETFIELD: { ExceptionDispatchBlock handler = handleExceptions(blockMap, bci); @@ -640,18 +686,16 @@ public final class BciBlockMapping { private BciBlock makeBlock(BciBlock[] blockMap, int startBci) { BciBlock oldBlock = blockMap[startBci]; if (oldBlock == null) { - BciBlock newBlock = new BciBlock(); + BciBlock newBlock = new BciBlock(startBci); blocksNotYetAssignedId++; - newBlock.startBci = startBci; blockMap[startBci] = newBlock; return newBlock; } else if (oldBlock.startBci != startBci) { // Backward branch into the middle of an already processed block. // Add the correct fall-through successor. - BciBlock newBlock = new BciBlock(); + BciBlock newBlock = new BciBlock(startBci); blocksNotYetAssignedId++; - newBlock.startBci = startBci; newBlock.endBci = oldBlock.endBci; for (BciBlock oldSuccessor : oldBlock.getSuccessors()) { newBlock.addSuccessor(oldSuccessor); @@ -747,6 +791,7 @@ public final class BciBlockMapping { private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) { ExceptionDispatchBlock lastHandler = null; + int dispatchBlocks = 0; for (int i = exceptionHandlers.length - 1; i >= 0; i--) { ExceptionHandler h = exceptionHandlers[i]; @@ -754,17 +799,14 @@ public final class BciBlockMapping { if (h.isCatchAll()) { // Discard all information about succeeding exception handlers, since they can // never be reached. + dispatchBlocks = 0; lastHandler = null; } // We do not reuse exception dispatch blocks, because nested exception handlers // might have problems reasoning about the correct frame state. - ExceptionDispatchBlock curHandler = new ExceptionDispatchBlock(); - blocksNotYetAssignedId++; - curHandler.startBci = -1; - curHandler.endBci = -1; - curHandler.deoptBci = bci; - curHandler.handler = h; + ExceptionDispatchBlock curHandler = new ExceptionDispatchBlock(h, bci); + dispatchBlocks++; curHandler.addSuccessor(blockMap[h.getHandlerBCI()]); if (lastHandler != null) { curHandler.addSuccessor(lastHandler); @@ -772,6 +814,7 @@ public final class BciBlockMapping { lastHandler = curHandler; } } + blocksNotYetAssignedId += dispatchBlocks; return lastHandler; } @@ -827,10 +870,8 @@ public final class BciBlockMapping { assert next == newBlocks.length - 1; // Add unwind block. - ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock(); - unwindBlock.startBci = -1; - unwindBlock.endBci = -1; - unwindBlock.deoptBci = code.getMethod().isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI; + int deoptBci = code.getMethod().isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI; + ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock(deoptBci); unwindBlock.setId(newBlocks.length - 1); newBlocks[newBlocks.length - 1] = unwindBlock; @@ -858,44 +899,56 @@ public final class BciBlockMapping { public void log(BciBlock[] blockMap, String name) { if (debug.isLogEnabled()) { - String n = System.lineSeparator(); - StringBuilder sb = new StringBuilder(debug.getCurrentScopeName()).append("BlockMap ").append(name).append(" :"); - sb.append(n); - Iterable it; - if (blocks == null) { - it = new HashSet<>(Arrays.asList(blockMap)); - } else { - it = Arrays.asList(blocks); - } - for (BciBlock b : it) { - if (b == null) { - continue; - } - sb.append("B").append(b.getId()).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")"); - if (b.isLoopHeader) { - sb.append(" LoopHeader"); - } - if (b.isExceptionEntry) { - sb.append(" ExceptionEntry"); - } - sb.append(n).append(" Sux : "); - for (BciBlock s : b.getSuccessors()) { - sb.append("B").append(s.getId()).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")"); - if (s.isExceptionEntry) { - sb.append("!"); - } - sb.append(" "); - } - sb.append(n).append(" Loop : "); - for (int pos : b.loopIdIterable()) { - sb.append("B").append(loopHeaders[pos].getId()).append(" "); - } - sb.append(n); - } - debug.log("%s", sb); + debug.log("%sBlockMap %s: %n%s", debug.getCurrentScopeName(), name, toString(blockMap, loopHeaders)); } } + public static String toString(BciBlock[] blockMap, BciBlock[] loopHeadersMap) { + StringBuilder sb = new StringBuilder(); + for (BciBlock b : blockMap) { + if (b == null) { + continue; + } + sb.append("B").append(b.getId()).append("[").append(b.startBci).append("..").append(b.endBci).append("]"); + if (b.isLoopHeader) { + sb.append(" LoopHeader"); + } + if (b.isExceptionEntry) { + sb.append(" ExceptionEntry"); + } + if (b instanceof ExceptionDispatchBlock) { + sb.append(" ExceptionDispatch"); + } + if (!b.successors.isEmpty()) { + sb.append(" Successors=["); + for (BciBlock s : b.getSuccessors()) { + if (sb.charAt(sb.length() - 1) != '[') { + sb.append(", "); + } + sb.append("B").append(s.getId()); + } + sb.append("]"); + } + if (b.loops != 0L) { + sb.append(" Loops=["); + for (int pos : b.loopIdIterable()) { + if (sb.charAt(sb.length() - 1) == '[') { + sb.append(", "); + } + sb.append("B").append(loopHeadersMap[pos].getId()); + } + sb.append("]"); + } + sb.append(System.lineSeparator()); + } + return sb.toString(); + } + + @Override + public String toString() { + return toString(blocks, loopHeaders); + } + /** * Get the header block for a loop index. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index 45b7da7cec6..9a553709b08 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -265,8 +265,8 @@ import java.util.Comparator; import java.util.Formatter; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeDisassembler; @@ -297,8 +297,10 @@ import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.debug.MethodFilter; import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.graph.Node; @@ -325,6 +327,7 @@ import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.FullInfopointNode; import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.InliningLog; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.InvokeNode; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; @@ -414,7 +417,7 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.util.ValueMergeUtil; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodeFrame; @@ -454,10 +457,16 @@ public class BytecodeParser implements GraphBuilderContext { /** * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set - * to trace the frame state before each bytecode instruction as it is parsed. + * to emit the frame state for each traced bytecode instruction. */ public static final int TRACELEVEL_STATE = 2; + /** + * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set + * to emit the block map for each traced method. + */ + public static final int TRACELEVEL_BLOCKMAP = 3; + /** * Meters the number of actual bytecodes parsed. */ @@ -681,6 +690,7 @@ public class BytecodeParser implements GraphBuilderContext { private ValueNode originalReceiver; private final boolean eagerInitializing; private final boolean uninitializedIsError; + private final int traceLevel; protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { @@ -714,12 +724,6 @@ public class BytecodeParser implements GraphBuilderContext { assert code.getCode() != null : "method must contain bytecodes: " + method; - if (TraceBytecodeParserLevel.getValue(options) != 0) { - if (!Assertions.assertionsEnabled()) { - throw new IllegalArgumentException("A non-zero " + TraceBytecodeParserLevel.getName() + " value requires assertions to be enabled"); - } - } - if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { lnt = code.getLineNumberTable(); previousLineNumber = -1; @@ -729,6 +733,24 @@ public class BytecodeParser implements GraphBuilderContext { if (graphBuilderConfig.trackNodeSourcePosition() || (parent != null && parent.graph.trackNodeSourcePosition())) { graph.setTrackNodeSourcePosition(); } + + int level = TraceBytecodeParserLevel.getValue(options); + this.traceLevel = level != 0 ? refineTraceLevel(level) : 0; + } + + private int refineTraceLevel(int level) { + ResolvedJavaMethod tmethod = graph.method(); + if (tmethod == null) { + tmethod = method; + } + String filterValue = DebugOptions.MethodFilter.getValue(options); + if (filterValue != null) { + MethodFilter[] filters = MethodFilter.parse(filterValue); + if (!MethodFilter.matches(filters, tmethod)) { + return 0; + } + } + return level; } protected GraphBuilderPhase.Instance getGraphBuilderInstance() { @@ -847,7 +869,7 @@ public class BytecodeParser implements GraphBuilderContext { currentBlock = blockMap.getStartBlock(); setEntryState(startBlock, frameState); - if (startBlock.isLoopHeader) { + if (startBlock.isLoopHeader()) { appendGoto(startBlock); } else { setFirstInstruction(startBlock, lastInstr); @@ -1676,6 +1698,7 @@ public class BytecodeParser implements GraphBuilderContext { targetMethod = originalMethod; } Invoke invoke = createNonInlinedInvoke(edgeAction, invokeBci, args, targetMethod, invokeKind, resultType, returnType, profile); + graph.getInliningLog().addDecision(invoke, false, "GraphBuilderPhase", null, null, "bytecode parser did not replace invoke"); if (partialIntrinsicExit) { // This invoke must never be later inlined as it might select the intrinsic graph. // Until there is a mechanism to guarantee that any late inlining will not select @@ -2172,60 +2195,80 @@ public class BytecodeParser implements GraphBuilderContext { } private boolean inline(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, BytecodeProvider intrinsicBytecodeProvider, ValueNode[] args) { - IntrinsicContext intrinsic = this.intrinsicContext; + try (InliningLog.RootScope scope = graph.getInliningLog().openRootScope(targetMethod, bci())) { + IntrinsicContext intrinsic = this.intrinsicContext; - if (intrinsic == null && !graphBuilderConfig.insertFullInfopoints() && - targetMethod.equals(inlinedMethod) && - (targetMethod.getModifiers() & (STATIC | SYNCHRONIZED)) == 0 && - tryFastInlineAccessor(args, targetMethod)) { - return true; - } - - if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) { - if (intrinsic.isCompilationRoot()) { - // A root compiled intrinsic needs to deoptimize - // if the slow path is taken. During frame state - // assignment, the deopt node will get its stateBefore - // from the start node of the intrinsic - append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); - printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)"); + if (intrinsic == null && !graphBuilderConfig.insertFullInfopoints() && + targetMethod.equals(inlinedMethod) && + (targetMethod.getModifiers() & (STATIC | SYNCHRONIZED)) == 0 && + tryFastInlineAccessor(args, targetMethod)) { return true; - } else { - if (intrinsic.getOriginalMethod().isNative()) { - printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)"); - return false; - } - if (canInlinePartialIntrinsicExit() && InlinePartialIntrinsicExitDuringParsing.getValue(options)) { - // Otherwise inline the original method. Any frame state created - // during the inlining will exclude frame(s) in the - // intrinsic method (see FrameStateBuilder.create(int bci)). - notifyBeforeInline(inlinedMethod); - printInlining(targetMethod, inlinedMethod, true, "partial intrinsic exit (bytecode parsing)"); - parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null); - notifyAfterInline(inlinedMethod); + } + + if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) { + if (intrinsic.isCompilationRoot()) { + // A root compiled intrinsic needs to deoptimize + // if the slow path is taken. During frame state + // assignment, the deopt node will get its stateBefore + // from the start node of the intrinsic + append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); + printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)"); + if (scope != null) { + graph.getInliningLog().addDecision(scope.getInvoke(), true, "GraphBuilderPhase", null, null, "compilation root"); + } return true; } else { - printInlining(targetMethod, inlinedMethod, false, "partial intrinsic exit (bytecode parsing)"); + if (intrinsic.getOriginalMethod().isNative()) { + printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)"); + if (scope != null) { + graph.getInliningLog().addDecision(scope.getInvoke(), false, "GraphBuilderPhase", null, null, "native method"); + } + return false; + } + if (canInlinePartialIntrinsicExit() && InlinePartialIntrinsicExitDuringParsing.getValue(options)) { + // Otherwise inline the original method. Any frame state created + // during the inlining will exclude frame(s) in the + // intrinsic method (see FrameStateBuilder.create(int bci)). + notifyBeforeInline(inlinedMethod); + printInlining(targetMethod, inlinedMethod, true, "partial intrinsic exit (bytecode parsing)"); + if (scope != null) { + graph.getInliningLog().addDecision(scope.getInvoke(), true, "GraphBuilderPhase", null, null, "partial intrinsic exit"); + } + parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null); + notifyAfterInline(inlinedMethod); + return true; + } else { + printInlining(targetMethod, inlinedMethod, false, "partial intrinsic exit (bytecode parsing)"); + if (scope != null) { + graph.getInliningLog().addDecision(scope.getInvoke(), false, "GraphBuilderPhase", null, null, "partial intrinsic exit"); + } + return false; + } + } + } else { + boolean isIntrinsic = intrinsicBytecodeProvider != null; + if (intrinsic == null && isIntrinsic) { + assert !inlinedMethod.equals(targetMethod); + intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING); + } + if (inlinedMethod.hasBytecodes()) { + notifyBeforeInline(inlinedMethod); + printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)"); + if (scope != null) { + graph.getInliningLog().addDecision(scope.getInvoke(), true, "GraphBuilderPhase", null, null, "inline method"); + } + parseAndInlineCallee(inlinedMethod, args, intrinsic); + notifyAfterInline(inlinedMethod); + } else { + printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)"); + if (scope != null) { + graph.getInliningLog().addDecision(scope.getInvoke(), false, "GraphBuilderPhase", null, null, "no bytecodes (abstract or native)"); + } return false; } } - } else { - boolean isIntrinsic = intrinsicBytecodeProvider != null; - if (intrinsic == null && isIntrinsic) { - assert !inlinedMethod.equals(targetMethod); - intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING); - } - if (inlinedMethod.hasBytecodes()) { - notifyBeforeInline(inlinedMethod); - printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)"); - parseAndInlineCallee(inlinedMethod, args, intrinsic); - notifyAfterInline(inlinedMethod); - } else { - printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)"); - return false; - } + return true; } - return true; } protected void notifyBeforeInline(ResolvedJavaMethod inlinedMethod) { @@ -2700,7 +2743,7 @@ public class BytecodeParser implements GraphBuilderContext { @SuppressWarnings("try") private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { assert block != null && state != null; - assert !block.isExceptionEntry || state.stackSize() == 1; + assert !block.isExceptionEntry() || state.stackSize() == 1; try (DebugCloseable context = openNodeContext(state, block.startBci)) { if (getFirstInstruction(block) == null) { @@ -2710,7 +2753,7 @@ public class BytecodeParser implements GraphBuilderContext { * again. */ FixedNode targetNode; - if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) { + if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader() && (currentBlock.loops & ~block.loops) == 0) { setFirstInstruction(block, lastInstr); lastInstr = null; } else { @@ -2729,11 +2772,11 @@ public class BytecodeParser implements GraphBuilderContext { // We already saw this block before, so we have to merge states. if (!getEntryState(block).isCompatibleWith(state)) { - throw bailout("stacks do not match; bytecodes would not verify"); + throw bailout(String.format("stacks do not match on merge from %d into %s; bytecodes would not verify:%nexpect: %s%nactual: %s", bci(), block, getEntryState(block), state)); } if (getFirstInstruction(block) instanceof LoopBeginNode) { - assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch"; + assert (block.isLoopHeader() && currentBlock.getId() >= block.getId()) : "must be backward branch"; /* * Backward loop edge. We need to create a special LoopEndNode and merge with the * loop begin node created before. @@ -2820,7 +2863,7 @@ public class BytecodeParser implements GraphBuilderContext { debug.log("Ignoring block %s", block); return; } - try (Indent indent = debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, firstInstruction, block.isLoopHeader)) { + try (Indent indent = debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, firstInstruction, block.isLoopHeader())) { lastInstr = firstInstruction; frameState = getEntryState(block); @@ -2949,11 +2992,11 @@ public class BytecodeParser implements GraphBuilderContext { @SuppressWarnings("try") protected void iterateBytecodesForBlock(BciBlock block) { - if (block.isLoopHeader) { + if (block.isLoopHeader()) { // Create the loop header block, which later will merge the backward branches of // the loop. controlFlowSplit = true; - LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr); + LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr, block.startBci); lastInstr = loopBegin; // Create phi functions for all local variables and operand stack slots. @@ -3007,8 +3050,9 @@ public class BytecodeParser implements GraphBuilderContext { // read the opcode int opcode = stream.currentBC(); - assert traceState(); - assert traceInstruction(bci, opcode, bci == block.startBci); + if (traceLevel != 0) { + traceInstruction(bci, opcode, bci == block.startBci); + } if (parent == null && bci == entryBCI) { if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) { throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported"); @@ -3038,7 +3082,7 @@ public class BytecodeParser implements GraphBuilderContext { lastInstr = finishInstruction(lastInstr, frameState); if (bci < endBCI) { if (bci > block.endBci) { - assert !block.getSuccessor(0).isExceptionEntry; + assert !block.getSuccessor(0).isExceptionEntry(); assert block.numNormalSuccessors() == 1; // we fell through to the next block, add a goto and break appendGoto(block.getSuccessor(0)); @@ -3097,16 +3141,19 @@ public class BytecodeParser implements GraphBuilderContext { return parsingIntrinsic(); } - private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) { - EndNode preLoopEnd = graph.add(new EndNode()); - LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); - if (disableLoopSafepoint()) { - loopBegin.disableSafepoint(); + @SuppressWarnings("try") + private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext, int startBci) { + try (DebugCloseable context = openNodeContext(frameState, startBci)) { + EndNode preLoopEnd = graph.add(new EndNode()); + LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); + if (disableLoopSafepoint()) { + loopBegin.disableSafepoint(); + } + fixedWithNext.setNext(preLoopEnd); + // Add the single non-loop predecessor of the loop header. + loopBegin.addForwardEnd(preLoopEnd); + return loopBegin; } - fixedWithNext.setNext(preLoopEnd); - // Add the single non-loop predecessor of the loop header. - loopBegin.addForwardEnd(preLoopEnd); - return loopBegin; } /** @@ -3126,13 +3173,6 @@ public class BytecodeParser implements GraphBuilderContext { } } - private boolean traceState() { - if (TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_STATE) { - frameState.traceState(); - } - return true; - } - protected void genIf(ValueNode x, Condition cond, ValueNode y) { assert x.getStackKind() == y.getStackKind(); assert currentBlock.getSuccessorCount() == 2; @@ -3249,19 +3289,23 @@ public class BytecodeParser implements GraphBuilderContext { } if (isNeverExecutedCode(probability)) { - append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true)); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore); + if (!graph.isOSR() || getParent() != null || graph.getEntryBCI() != trueBlock.startBci) { + append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true)); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore); + } + appendGoto(falseBlock); + return; } - appendGoto(falseBlock); - return; } else if (isNeverExecutedCode(1 - probability)) { - append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false)); - if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { - profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore); + if (!graph.isOSR() || getParent() != null || graph.getEntryBCI() != falseBlock.startBci) { + append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false)); + if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { + profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore); + } + appendGoto(trueBlock); + return; } - appendGoto(trueBlock); - return; } if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { @@ -4677,15 +4721,25 @@ public class BytecodeParser implements GraphBuilderContext { return frameState; } - protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { - if (TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_INSTRUCTIONS) { - traceInstructionHelper(bci, opcode, blockStart); - } - return true; - } + private boolean firstTraceEmitted; - private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { + protected void traceInstruction(int bci, int opcode, boolean blockStart) { + String indent = new String(new char[getDepth() * 2]).replace('\0', ' '); StringBuilder sb = new StringBuilder(40); + String nl = System.lineSeparator(); + if (!firstTraceEmitted) { + sb.append(indent).append(method.format("Parsing %H.%n(%p)%r")).append(nl); + if (traceLevel >= TRACELEVEL_BLOCKMAP) { + sb.append(indent).append("Blocks:").append(nl); + String bm = blockMap.toString().replace(nl, nl + indent + " "); + sb.append(indent).append(" ").append(bm).append(nl); + } + firstTraceEmitted = true; + } + if (traceLevel >= TRACELEVEL_STATE) { + sb.append(indent).append(frameState).append(nl); + } + sb.append(indent); sb.append(blockStart ? '+' : '|'); if (bci < 10) { sb.append(" "); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java index 53d6074f2e8..ac3a628733c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java @@ -35,8 +35,10 @@ import org.graalvm.compiler.options.OptionKey; public class BytecodeParserOptions { // @formatter:off @Option(help = "The trace level for the bytecode parser. A value of 1 enables instruction tracing " + - "and any greater value emits a frame state trace just prior to an instruction trace. " + - "This option requires assertions to be enabled.", type = OptionType.Debug) + "and any greater value emits a frame state trace just prior to each instruction trace." + + "Instruction tracing output from multiple compiler threads will be interleaved so " + + "use of this option make most sense for single threaded compilation. " + + "The MethodFilter option can be used to refine tracing to selected methods.", type = OptionType.Debug) public static final OptionKey TraceBytecodeParserLevel = new OptionKey<>(0); @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java index c24565a5dfb..729266f5f2c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java @@ -26,7 +26,7 @@ import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilit import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.ControlSplitNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java index 0e5d1712def..510323a9d63 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java @@ -46,7 +46,6 @@ import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.java.BciBlockMapping.BciBlock; import org.graalvm.compiler.nodeinfo.Verbosity; @@ -982,16 +981,4 @@ public final class FrameStateBuilder implements SideEffectsState { } sideEffects.add(sideEffect); } - - public void traceState() { - TTY.println("| state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod()); - for (int i = 0; i < localsSize(); ++i) { - ValueNode value = locals[i]; - TTY.println("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); - } - for (int i = 0; i < stackSize(); ++i) { - ValueNode value = stack[i]; - TTY.println("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); - } - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java index dacfbf03e93..fc507200919 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/LocalLiveness.java @@ -220,7 +220,7 @@ public abstract class LocalLiveness { protected abstract void storeOne(int blockID, int local); private void computeLocalLiveness(BytecodeStream stream, BciBlock block) { - if (block.startBci < 0 || block.endBci < 0) { + if (block.isExceptionDispatch()) { return; } int blockID = block.getId(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java new file mode 100644 index 00000000000..e262bb51441 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.lir.aarch64; + +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; +import sun.misc.Unsafe; + +/** + * Emits code which compares two arrays lexicographically. If the CPU supports any vector + * instructions specialized code is emitted to leverage these instructions. + */ +@Opcode("ARRAY_COMPARE_TO") +public final class AArch64ArrayCompareToOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64ArrayCompareToOp.class); + + private final JavaKind kind1; + private final JavaKind kind2; + + private final int array1BaseOffset; + private final int array2BaseOffset; + + @Def({REG}) protected Value resultValue; + + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Use({REG}) protected Value length1Value; + @Use({REG}) protected Value length2Value; + @Temp({REG}) protected Value length1ValueTemp; + @Temp({REG}) protected Value length2ValueTemp; + + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + @Temp({REG}) protected Value temp3; + @Temp({REG}) protected Value temp4; + @Temp({REG}) protected Value temp5; + @Temp({REG}) protected Value temp6; + + public AArch64ArrayCompareToOp(LIRGeneratorTool tool, JavaKind kind1, JavaKind kind2, Value result, Value array1, Value array2, Value length1, Value length2) { + super(TYPE); + this.kind1 = kind1; + this.kind2 = kind2; + + // Both offsets should be the same but better be safe than sorry. + Class array1Class = Array.newInstance(kind1.toJavaClass(), 0).getClass(); + Class array2Class = Array.newInstance(kind2.toJavaClass(), 0).getClass(); + this.array1BaseOffset = UNSAFE.arrayBaseOffset(array1Class); + this.array2BaseOffset = UNSAFE.arrayBaseOffset(array2Class); + + this.resultValue = result; + + this.array1Value = array1; + this.array2Value = array2; + + /* + * The length values are inputs but are also killed like temporaries so need both Use and + * Temp annotations, which will only work with fixed registers. + */ + + this.length1Value = length1; + this.length2Value = length2; + this.length1ValueTemp = length1; + this.length2ValueTemp = length2; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp3 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp4 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp5 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + this.temp6 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); + } + + private static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } + + @Override + protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + + Register result = asRegister(resultValue); + Register length1 = asRegister(length1Value); + Register length2 = asRegister(length2Value); + + Register array1 = asRegister(temp1); + Register array2 = asRegister(temp2); + Register length = asRegister(temp3); + Register temp = asRegister(temp4); + Register tailCount = asRegister(temp5); + Register vecCount = asRegister(temp6); + + // Checkstyle: stop + final Label BREAK_LABEL = new Label(); + final Label STRING_DIFFER_LABEL = new Label(); + final Label LENGTH_DIFFER_LABEL = new Label(); + final Label MAIN_LOOP_LABEL = new Label(); + final Label COMPARE_SHORT_LABEL = new Label(); + // Checkstyle: resume + + // Checkstyle: stop + int CHAR_SIZE_BYTES = 1; + int VECTOR_SIZE_BYTES = 8; + int VECTOR_COUNT_BYTES = 8; + // Checkstyle: resume + + // Byte is expanded to short if we compare strings with different encoding + if (kind1 != kind2 || kind1 == JavaKind.Char) { + CHAR_SIZE_BYTES = 2; + } + + if (kind1 != kind2) { + VECTOR_COUNT_BYTES = 4; + } + + // Load array base addresses. + masm.lea(array1, AArch64Address.createUnscaledImmediateAddress(asRegister(array1Value), array1BaseOffset)); + masm.lea(array2, AArch64Address.createUnscaledImmediateAddress(asRegister(array2Value), array2BaseOffset)); + + // Calculate minimal length in chars for different kind case + // Conditions could be squashed but lets keep it readable + if (kind1 != kind2) { + masm.lshr(64, length2, length2, 1); + } + + if (kind1 == kind2 && kind1 == JavaKind.Char) { + masm.lshr(64, length1, length1, 1); + masm.lshr(64, length2, length2, 1); + } + + masm.cmp(64, length1, length2); + masm.cmov(64, length, length1, length2, ConditionFlag.LT); + + // One of strings is empty + masm.cbz(64, length, LENGTH_DIFFER_LABEL); + + // Go back to bytes if necessary + if (kind1 != kind2 || kind1 == JavaKind.Char) { + masm.shl(64, length, length, 1); + } + + masm.mov(64, vecCount, zr); + masm.and(64, tailCount, length, VECTOR_SIZE_BYTES - 1); // tail count (in bytes) + masm.ands(64, length, length, ~(VECTOR_SIZE_BYTES - 1)); // vector count (in bytes) + + // Length of string is less than VECTOR_SIZE, go to simple compare + masm.branchConditionally(ConditionFlag.EQ, COMPARE_SHORT_LABEL); + + // MAIN_LOOP - read strings by 8 byte. + masm.bind(MAIN_LOOP_LABEL); + if (kind1 != kind2) { + // Load 32 bits ad unpack it to entire 64bit register + masm.ldr(32, result, AArch64Address.createRegisterOffsetAddress(array1, vecCount, false)); + masm.ubfm(64, temp, result, 0, 7); + masm.lshr(64, result, result, 8); + masm.bfm(64, temp, result, 48, 7); + masm.lshr(64, result, result, 8); + masm.bfm(64, temp, result, 32, 7); + masm.lshr(64, result, result, 8); + masm.bfm(64, temp, result, 16, 7); + // Unpacked value placed in temp now + + masm.shl(64, result, vecCount, 1); + masm.ldr(64, result, AArch64Address.createRegisterOffsetAddress(array2, result, false)); + } else { + masm.ldr(64, temp, AArch64Address.createRegisterOffsetAddress(array1, vecCount, false)); + masm.ldr(64, result, AArch64Address.createRegisterOffsetAddress(array2, vecCount, false)); + } + masm.eor(64, result, temp, result); + masm.cbnz(64, result, STRING_DIFFER_LABEL); + masm.add(64, vecCount, vecCount, VECTOR_COUNT_BYTES); + masm.cmp(64, vecCount, length); + masm.branchConditionally(ConditionFlag.LT, MAIN_LOOP_LABEL); + // End of MAIN_LOOP + + // Strings are equal and no TAIL go to END + masm.cbz(64, tailCount, LENGTH_DIFFER_LABEL); + + // Compaire tail of long string ... + masm.lea(array1, AArch64Address.createRegisterOffsetAddress(array1, length, false)); + masm.lea(array2, AArch64Address.createRegisterOffsetAddress(array2, length, false)); + + // ... or string less than vector length + masm.bind(COMPARE_SHORT_LABEL); + for (int i = 0; i < VECTOR_COUNT_BYTES; i += CHAR_SIZE_BYTES) { + if (kind1 != kind2) { + masm.ldr(8, temp, AArch64Address.createUnscaledImmediateAddress(array1, i / 2)); + } else { + masm.ldr(8 * CHAR_SIZE_BYTES, temp, AArch64Address.createUnscaledImmediateAddress(array1, i)); + } + + masm.ldr(8 * CHAR_SIZE_BYTES, result, AArch64Address.createUnscaledImmediateAddress(array2, i)); + + if (kind1 != kind2 && kind1 == JavaKind.Char) { + // Weird swap of substraction order + masm.subs(64, result, result, temp); + } else { + masm.subs(64, result, temp, result); + } + + masm.branchConditionally(ConditionFlag.NE, BREAK_LABEL); + masm.subs(64, tailCount, tailCount, CHAR_SIZE_BYTES); + masm.branchConditionally(ConditionFlag.EQ, LENGTH_DIFFER_LABEL); + } + + // STRING_DIFFER extract exact value of a difference + masm.bind(STRING_DIFFER_LABEL); + masm.rbit(64, tailCount, result); + masm.clz(64, vecCount, tailCount); + masm.and(64, vecCount, vecCount, ~((8 * CHAR_SIZE_BYTES) - 1)); // Round to byte or short + + masm.eor(64, result, temp, result); + masm.ashr(64, result, result, vecCount); + masm.ashr(64, temp, temp, vecCount); + + masm.and(64, result, result, 0xFFFF >>> (16 - (8 * CHAR_SIZE_BYTES))); // 0xFF or 0xFFFF + masm.and(64, temp, temp, 0xFFFF >>> (16 - (8 * CHAR_SIZE_BYTES))); + + masm.sub(64, result, temp, result); + masm.branchConditionally(ConditionFlag.AL, BREAK_LABEL); + // End of STRING_DIFFER + + // Strings are equials up to length, + // return length difference in chars + masm.bind(LENGTH_DIFFER_LABEL); + if (kind1 != kind2 && kind1 == JavaKind.Char) { + // Weird swap of substraction order + masm.sub(64, result, length2, length1); + } else { + masm.sub(64, result, length1, length2); + } + + // We are done + masm.bind(BREAK_LABEL); + } + +} // class diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AtomicMove.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AtomicMove.java new file mode 100644 index 00000000000..d357f52bd69 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AtomicMove.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 org.graalvm.compiler.lir.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.aarch64.AArch64.CPUFeature; +import jdk.vm.ci.aarch64.AArch64.Flag; +import jdk.vm.ci.aarch64.AArch64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; + +public class AArch64AtomicMove { + /** + * Compare and swap instruction. Does the following atomically: + * CAS(newVal, expected, address): + * oldVal = *address + * if oldVal == expected: + * *address = newVal + * return oldVal + * + */ + @Opcode("CAS") + public static class CompareAndSwapOp extends AArch64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); + + @Def protected AllocatableValue resultValue; + @Alive protected Value expectedValue; + @Alive protected AllocatableValue newValue; + @Alive protected AllocatableValue addressValue; + @Temp protected AllocatableValue scratchValue; + + public CompareAndSwapOp(AllocatableValue result, Value expectedValue, AllocatableValue newValue, AllocatableValue addressValue, AllocatableValue scratch) { + super(TYPE); + this.resultValue = result; + this.expectedValue = expectedValue; + this.newValue = newValue; + this.addressValue = addressValue; + this.scratchValue = scratch; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + AArch64Kind kind = (AArch64Kind) expectedValue.getPlatformKind(); + assert kind.isInteger(); + final int size = kind.getSizeInBytes() * Byte.SIZE; + + Register address = asRegister(addressValue); + Register result = asRegister(resultValue); + Register newVal = asRegister(newValue); + if (masm.supports(CPUFeature.LSE) || masm.isFlagSet(Flag.UseLSE)) { + Register expected = asRegister(expectedValue); + masm.mov(size, result, expected); + masm.cas(size, expected, newVal, address, true /*acquire*/, true /*release*/); + AArch64Compare.gpCompare(masm, resultValue, expectedValue); + } else { + // We could avoid using a scratch register here, by reusing resultValue for the stlxr + // success flag and issue a mov resultValue, expectedValue in case of success before + // returning. + Register scratch = asRegister(scratchValue); + Label retry = new Label(); + Label fail = new Label(); + masm.bind(retry); + masm.ldaxr(size, result, address); + AArch64Compare.gpCompare(masm, resultValue, expectedValue); + masm.branchConditionally(AArch64Assembler.ConditionFlag.NE, fail); + masm.stlxr(size, scratch, newVal, address); + // if scratch == 0 then write successful, else retry. + masm.cbnz(32, scratch, retry); + masm.bind(fail); + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java index d6349aeda43..a22347d7cb2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java @@ -37,9 +37,7 @@ import static jdk.vm.ci.code.ValueUtil.asStackSlot; import static jdk.vm.ci.code.ValueUtil.isRegister; import static jdk.vm.ci.code.ValueUtil.isStackSlot; -import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.aarch64.AArch64Address; -import org.graalvm.compiler.asm.aarch64.AArch64Assembler; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; import org.graalvm.compiler.core.common.LIRKind; @@ -339,60 +337,6 @@ public class AArch64Move { } } - /** - * Compare and swap instruction. Does the following atomically: - * CAS(newVal, expected, address): - * oldVal = *address - * if oldVal == expected: - * *address = newVal - * return oldVal - * - */ - @Opcode("CAS") - public static class CompareAndSwapOp extends AArch64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); - - @Def protected AllocatableValue resultValue; - @Alive protected Value expectedValue; - @Alive protected AllocatableValue newValue; - @Alive protected AllocatableValue addressValue; - @Temp protected AllocatableValue scratchValue; - - public CompareAndSwapOp(AllocatableValue result, Value expectedValue, AllocatableValue newValue, AllocatableValue addressValue, AllocatableValue scratch) { - super(TYPE); - this.resultValue = result; - this.expectedValue = expectedValue; - this.newValue = newValue; - this.addressValue = addressValue; - this.scratchValue = scratch; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - AArch64Kind kind = (AArch64Kind) expectedValue.getPlatformKind(); - assert kind.isInteger(); - final int size = kind.getSizeInBytes() * Byte.SIZE; - - Register address = asRegister(addressValue); - Register result = asRegister(resultValue); - Register newVal = asRegister(newValue); - Register scratch = asRegister(scratchValue); - // We could avoid using a scratch register here, by reusing resultValue for the stlxr - // success flag and issue a mov resultValue, expectedValue in case of success before - // returning. - Label retry = new Label(); - Label fail = new Label(); - masm.bind(retry); - masm.ldaxr(size, result, address); - AArch64Compare.gpCompare(masm, resultValue, expectedValue); - masm.branchConditionally(AArch64Assembler.ConditionFlag.NE, fail); - masm.stlxr(size, scratch, newVal, address); - // if scratch == 0 then write successful, else retry. - masm.cbnz(32, scratch, retry); - masm.bind(fail); - } - } - private static void emitStore(@SuppressWarnings("unused") CompilationResultBuilder crb, AArch64MacroAssembler masm, AArch64Kind kind, AArch64Address dst, Value src) { int destSize = kind.getSizeInBytes() * Byte.SIZE; if (kind.isInteger()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java index ac9ef6094e3..54f280ff688 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java @@ -71,8 +71,10 @@ public final class AMD64ArrayCompareToOp extends AMD64LIRInstruction { @Def({REG}) protected Value resultValue; @Alive({REG}) protected Value array1Value; @Alive({REG}) protected Value array2Value; - @Alive({REG}) protected Value length1Value; - @Alive({REG}) protected Value length2Value; + @Use({REG}) protected Value length1Value; + @Use({REG}) protected Value length2Value; + @Temp({REG}) protected Value length1ValueTemp; + @Temp({REG}) protected Value length2ValueTemp; @Temp({REG}) protected Value temp1; @Temp({REG}) protected Value temp2; @@ -92,8 +94,14 @@ public final class AMD64ArrayCompareToOp extends AMD64LIRInstruction { this.resultValue = result; this.array1Value = array1; this.array2Value = array2; + /* + * The length values are inputs but are also killed like temporaries so need both Use and + * Temp annotations, which will only work with fixed registers. + */ this.length1Value = length1; this.length2Value = length2; + this.length1ValueTemp = length1; + this.length2ValueTemp = length2; // Allocate some temporaries. this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java index a8c20095238..3c6da0c33a0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java @@ -28,7 +28,7 @@ import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; import java.util.Arrays; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.LIRValueUtil; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java index 7c76f28d054..50f538fd6f4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.lir.amd64; import static org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp.prune; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java index f5a0e93b26c..bb9eb1f56e2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java @@ -78,8 +78,8 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Assembler.LabelHint; import org.graalvm.compiler.asm.Label; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java index ba59423a4bf..6c698cd0974 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java @@ -29,7 +29,7 @@ import static org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer.DUMMY; import java.util.Arrays; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.sparc.SPARCAddress; import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java index f3b907afd87..c91d545e8c4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java @@ -27,7 +27,7 @@ import static org.junit.Assert.assertTrue; import java.util.HashSet; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue; import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java index 53dd628c755..7d0668a46cd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java @@ -33,9 +33,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.core.common.FieldIntrospection; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.FieldsScanner; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java index 9444a05384c..83073884d98 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java @@ -30,8 +30,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.debug.CounterKey; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java index 39d5c1a6555..5507def746e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java @@ -31,7 +31,7 @@ import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; import java.util.ArrayList; import java.util.EnumSet; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.debug.GraalError; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValuesAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/RegisterAllocationPhase.java similarity index 64% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValuesAccess.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/RegisterAllocationPhase.java index cb2589d4f8d..b37dea5a25b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValuesAccess.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/RegisterAllocationPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,19 +20,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package org.graalvm.compiler.options; +package org.graalvm.compiler.lir.alloc; + +import org.graalvm.compiler.lir.phases.AllocationPhase; /** - * Defines a service that supplies values for options. The values supplied may come from a source - * such as system properties or a command line. - * - * This mechanism for obtaining option values must only be used if there is no other more local - * context from which option values can be obtained. + * Marker class for register allocation phases. */ -public interface OptionValuesAccess { +public abstract class RegisterAllocationPhase extends AllocationPhase { + private boolean neverSpillConstants; - /** - * Gets the option values available via this service. - */ - OptionValues getOptions(); + public void setNeverSpillConstants(boolean neverSpillConstants) { + this.neverSpillConstants = neverSpillConstants; + } + + public boolean getNeverSpillConstants() { + return neverSpillConstants; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java index 92146c1c49d..58574d93418 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java @@ -35,7 +35,7 @@ import java.util.Arrays; import java.util.BitSet; import java.util.EnumSet; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java index 4ab4f8972c4..9b4efabae62 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java @@ -35,8 +35,8 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.EnumSet; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; @@ -160,12 +160,14 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops()); try { + final BitSet liveGenScratch = new BitSet(liveSize); + final BitSet liveKillScratch = new BitSet(liveSize); // iterate all blocks for (final AbstractBlockBase block : allocator.sortedBlocks()) { try (Indent indent = debug.logAndIndent("compute local live sets for block %s", block)) { - final BitSet liveGen = new BitSet(liveSize); - final BitSet liveKill = new BitSet(liveSize); + liveGenScratch.clear(); + liveKillScratch.clear(); ArrayList instructions = allocator.getLIR().getLIRforBlock(block); int numInst = instructions.size(); @@ -173,8 +175,8 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { ValueConsumer useConsumer = (operand, mode, flags) -> { if (isVariable(operand)) { int operandNum = allocator.operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); + if (!liveKillScratch.get(operandNum)) { + liveGenScratch.set(operandNum); if (debug.isLogEnabled()) { debug.log("liveGen for operand %d(%s)", operandNum, operand); } @@ -185,14 +187,14 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { } if (allocator.detailedAsserts) { - verifyInput(block, liveKill, operand); + verifyInput(block, liveKillScratch, operand); } }; ValueConsumer stateConsumer = (operand, mode, flags) -> { if (LinearScan.isVariableOrRegister(operand)) { int operandNum = allocator.operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); + if (!liveKillScratch.get(operandNum)) { + liveGenScratch.set(operandNum); if (debug.isLogEnabled()) { debug.log("liveGen in state for operand %d(%s)", operandNum, operand); } @@ -202,7 +204,7 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { ValueConsumer defConsumer = (operand, mode, flags) -> { if (isVariable(operand)) { int varNum = allocator.operandNumber(operand); - liveKill.set(varNum); + liveKillScratch.set(varNum); if (debug.isLogEnabled()) { debug.log("liveKill for operand %d(%s)", varNum, operand); } @@ -217,7 +219,7 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { * be processed in live sets. Process them only in debug mode so that * this can be checked */ - verifyTemp(liveKill, operand); + verifyTemp(liveKillScratch, operand); } }; @@ -239,10 +241,11 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { } // end of instruction iteration BlockData blockSets = allocator.getBlockData(block); - blockSets.liveGen = liveGen; - blockSets.liveKill = liveKill; - blockSets.liveIn = new BitSet(liveSize); - blockSets.liveOut = new BitSet(liveSize); + blockSets.liveGen = trimClone(liveGenScratch); + blockSets.liveKill = trimClone(liveKillScratch); + // sticky size, will get non-sticky in computeGlobalLiveSets + blockSets.liveIn = new BitSet(0); + blockSets.liveOut = new BitSet(0); if (debug.isLogEnabled()) { debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); @@ -292,7 +295,7 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { boolean changeOccurred; boolean changeOccurredInBlock; int iterationCount = 0; - BitSet liveOut = new BitSet(allocator.liveSetSize()); // scratch set for calculations + BitSet scratch = new BitSet(allocator.liveSetSize()); // scratch set for calculations /* * Perform a backward dataflow analysis to compute liveOut and liveIn for each block. @@ -315,22 +318,16 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { */ int n = block.getSuccessorCount(); if (n > 0) { - liveOut.clear(); + scratch.clear(); // block has successors if (n > 0) { for (AbstractBlockBase successor : block.getSuccessors()) { - liveOut.or(allocator.getBlockData(successor).liveIn); + scratch.or(allocator.getBlockData(successor).liveIn); } } - if (!blockSets.liveOut.equals(liveOut)) { - /* - * A change occurred. Swap the old and new live out sets to avoid - * copying. - */ - BitSet temp = blockSets.liveOut; - blockSets.liveOut = liveOut; - liveOut = temp; + if (!blockSets.liveOut.equals(scratch)) { + blockSets.liveOut = trimClone(scratch); changeOccurred = true; changeOccurredInBlock = true; @@ -344,13 +341,20 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { * * Note: liveIn has to be computed only in first iteration or if liveOut * has changed! + * + * Note: liveIn set can only grow, never shrink. No need to clear it. */ BitSet liveIn = blockSets.liveIn; - liveIn.clear(); + /* + * BitSet#or will call BitSet#ensureSize (since the bit set is of length + * 0 initially) and set sticky to false + */ liveIn.or(blockSets.liveOut); liveIn.andNot(blockSets.liveKill); liveIn.or(blockSets.liveGen); + liveIn.clone(); // trimToSize() + if (debug.isLogEnabled()) { debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); } @@ -384,6 +388,20 @@ public class LinearScanLifetimeAnalysisPhase extends LinearScanAllocationPhase { } } + /** + * Creates a trimmed copy a bit set. + * + * {@link BitSet#clone()} cannot be used since it will not {@linkplain BitSet#trimToSize trim} + * the array if the bit set is {@linkplain BitSet#sizeIsSticky sticky}. + */ + @SuppressWarnings("javadoc") + private static BitSet trimClone(BitSet set) { + BitSet trimmedSet = new BitSet(0); // zero-length words array, sticky + trimmedSet.or(set); // words size ensured to be words-in-use of set, + // also makes it non-sticky + return trimmedSet; + } + @SuppressWarnings("try") protected void reportFailure(int numBlocks) { try (DebugContext.Scope s = debug.forceLog()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java index e54c744ac44..8eada1c4fbe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanPhase.java @@ -23,26 +23,20 @@ package org.graalvm.compiler.lir.alloc.lsra; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; +import org.graalvm.compiler.lir.alloc.RegisterAllocationPhase; import org.graalvm.compiler.lir.alloc.lsra.ssa.SSALinearScan; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; -import org.graalvm.compiler.lir.phases.AllocationPhase; import jdk.vm.ci.code.TargetDescription; -public final class LinearScanPhase extends AllocationPhase { - - private boolean neverSpillConstants; - - public void setNeverSpillConstants(boolean neverSpillConstants) { - this.neverSpillConstants = neverSpillConstants; - } +public final class LinearScanPhase extends RegisterAllocationPhase { @Override protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) { MoveFactory spillMoveFactory = context.spillMoveFactory; RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig; - final LinearScan allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, lirGenRes.getLIR().linearScanOrder(), neverSpillConstants); + final LinearScan allocator = new SSALinearScan(target, lirGenRes, spillMoveFactory, registerAllocationConfig, lirGenRes.getLIR().linearScanOrder(), getNeverSpillConstants()); allocator.allocate(target, lirGenRes, context); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java index 0d031d189b2..73259f922c2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.lir.alloc.lsra; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java index e6267a0208a..711c6a52bda 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java @@ -28,8 +28,8 @@ import static jdk.vm.ci.code.ValueUtil.isRegister; import java.util.ArrayList; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java index b05b8c6023f..eb7a1d7763c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java @@ -30,10 +30,10 @@ import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.alloc.RegisterAllocationPhase; import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; -import org.graalvm.compiler.lir.phases.AllocationPhase; import org.graalvm.compiler.lir.ssa.SSAUtil; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -47,7 +47,7 @@ import jdk.vm.ci.meta.AllocatableValue; * "Trace-based Register Allocation in a JIT * Compiler" by Josef Eisl et al. */ -public final class TraceRegisterAllocationPhase extends AllocationPhase { +public final class TraceRegisterAllocationPhase extends RegisterAllocationPhase { public static class Options { // @formatter:off @@ -67,9 +67,20 @@ public final class TraceRegisterAllocationPhase extends AllocationPhase { public static final CounterKey globalStackSlots = DebugContext.counter("TraceRA[GlobalStackSlots]"); public static final CounterKey allocatedStackSlots = DebugContext.counter("TraceRA[AllocatedStackSlots]"); + private final TraceBuilderPhase traceBuilder; + private final GlobalLivenessAnalysisPhase livenessAnalysis; + + public TraceRegisterAllocationPhase() { + this.traceBuilder = new TraceBuilderPhase(); + this.livenessAnalysis = new GlobalLivenessAnalysisPhase(); + } + @Override @SuppressWarnings("try") protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) { + traceBuilder.apply(target, lirGenRes, context); + livenessAnalysis.apply(target, lirGenRes, context); + MoveFactory spillMoveFactory = context.spillMoveFactory; RegisterAllocationConfig registerAllocationConfig = context.registerAllocationConfig; LIR lir = lirGenRes.getLIR(); @@ -80,8 +91,8 @@ public final class TraceRegisterAllocationPhase extends AllocationPhase { TraceAllocationContext traceContext = new TraceAllocationContext(spillMoveFactory, registerAllocationConfig, resultTraces, livenessInfo); AllocatableValue[] cachedStackSlots = Options.TraceRACacheStackSlots.getValue(lir.getOptions()) ? new AllocatableValue[lir.numVariables()] : null; - // currently this is not supported - boolean neverSpillConstant = false; + boolean neverSpillConstant = getNeverSpillConstants(); + assert !neverSpillConstant : "currently this is not supported"; final TraceRegisterAllocationPolicy plan = DefaultTraceRegisterAllocationPolicy.allocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstant, livenessInfo, lir.getOptions()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java index 7abb15b7996..719b50f2470 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java @@ -32,8 +32,8 @@ import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.asm.AbstractAddress; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.code.CompilationResult; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java index 173135c0869..63d7fe2a4fa 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.lir.gen; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity; import org.graalvm.compiler.debug.DebugContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java index 005e8c0af51..9e1fad91f48 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java @@ -30,8 +30,8 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.lir.LIRInsertionBuffer; import org.graalvm.compiler.lir.LIRInstruction; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java index 1072b3e8b92..63360c8c06a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/AllocationStage.java @@ -27,8 +27,6 @@ import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.lir.alloc.AllocationStageVerifier; import org.graalvm.compiler.lir.alloc.lsra.LinearScanPhase; -import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessAnalysisPhase; -import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase; import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase; import org.graalvm.compiler.lir.dfa.LocationMarkerPhase; import org.graalvm.compiler.lir.dfa.MarkBasePointersPhase; @@ -42,8 +40,6 @@ public class AllocationStage extends LIRPhaseSuite { public AllocationStage(OptionValues options) { appendPhase(new MarkBasePointersPhase()); if (TraceRA.getValue(options)) { - appendPhase(new TraceBuilderPhase()); - appendPhase(new GlobalLivenessAnalysisPhase()); appendPhase(new TraceRegisterAllocationPhase()); } else { appendPhase(new LinearScanPhase()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java index 1a74fb46b16..31e250a040f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/EconomyAllocationStage.java @@ -25,8 +25,6 @@ package org.graalvm.compiler.lir.phases; import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; import org.graalvm.compiler.lir.alloc.lsra.LinearScanPhase; -import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessAnalysisPhase; -import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase; import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase; import org.graalvm.compiler.lir.dfa.LocationMarkerPhase; import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; @@ -36,8 +34,6 @@ import org.graalvm.compiler.options.OptionValues; public class EconomyAllocationStage extends LIRPhaseSuite { public EconomyAllocationStage(OptionValues options) { if (TraceRA.getValue(options)) { - appendPhase(new TraceBuilderPhase()); - appendPhase(new GlobalLivenessAnalysisPhase()); appendPhase(new TraceRegisterAllocationPhase()); } else { appendPhase(new LinearScanPhase()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java index 61671a71c7f..3bb527baa01 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java @@ -31,8 +31,8 @@ import java.util.BitSet; import java.util.Deque; import java.util.EnumSet; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.debug.CounterKey; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java index 7c671c89361..d40d067a3d6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java @@ -35,7 +35,7 @@ import java.util.EnumMap; import java.util.EnumSet; import java.util.PriorityQueue; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java index 0c428955ed8..7fef9744923 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.lir.util; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java index f1200f89532..45f1ad9a971 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java @@ -29,6 +29,7 @@ import static org.graalvm.compiler.loop.MathUtil.unsignedDivBefore; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.util.UnsignedLong; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.loop.InductionVariable.Direction; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.ConstantNode; @@ -223,34 +224,37 @@ public class CountedLoopInfo { return loop.loopBegin().getOverflowGuard(); } + @SuppressWarnings("try") public GuardingNode createOverFlowGuard() { GuardingNode overflowGuard = getOverFlowGuard(); if (overflowGuard != null) { return overflowGuard; } - IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT); - StructuredGraph graph = iv.valueNode().graph(); - CompareNode cond; // we use a negated guard with a < condition to achieve a >= - ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph); - if (iv.direction() == Direction.Up) { - ValueNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one)); - if (oneOff) { - v1 = sub(graph, v1, one); + try (DebugCloseable position = loop.loopBegin().withNodeSourcePosition()) { + IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT); + StructuredGraph graph = iv.valueNode().graph(); + CompareNode cond; // we use a negated guard with a < condition to achieve a >= + ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph); + if (iv.direction() == Direction.Up) { + ValueNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one)); + if (oneOff) { + v1 = sub(graph, v1, one); + } + cond = graph.unique(new IntegerLessThanNode(v1, end)); + } else { + assert iv.direction() == Direction.Down; + ValueNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode())); + if (oneOff) { + v1 = add(graph, v1, one); + } + cond = graph.unique(new IntegerLessThanNode(end, v1)); } - cond = graph.unique(new IntegerLessThanNode(v1, end)); - } else { - assert iv.direction() == Direction.Down; - ValueNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode())); - if (oneOff) { - v1 = add(graph, v1, one); - } - cond = graph.unique(new IntegerLessThanNode(end, v1)); + assert graph.getGuardsStage().allowsFloatingGuards(); + overflowGuard = graph.unique(new GuardNode(cond, AbstractBeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true, + JavaConstant.NULL_POINTER)); // TODO gd: use speculation + loop.loopBegin().setOverflowGuard(overflowGuard); + return overflowGuard; } - assert graph.getGuardsStage().allowsFloatingGuards(); - overflowGuard = graph.unique(new GuardNode(cond, AbstractBeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true, - JavaConstant.NULL_POINTER)); // TODO gd: use speculation - loop.loopBegin().setOverflowGuard(overflowGuard); - return overflowGuard; } public IntegerStamp getStamp() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java index 89c9cf51ff4..724dd82a97f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java @@ -26,9 +26,9 @@ import java.util.Collection; import java.util.LinkedList; import java.util.Queue; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.IntegerStamp; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java index 3485c3be0f5..8f9113a3919 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java @@ -27,7 +27,7 @@ import java.util.Collections; import java.util.Deque; import java.util.Iterator; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java index 989a5fa7c52..5aff9698e1b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java @@ -26,8 +26,8 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java index 0a6d267d3a4..81979d8d823 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.loop; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Graph; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java index c2f07108237..91872ae9106 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java @@ -27,9 +27,9 @@ import java.util.Collection; import java.util.LinkedList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.LoopBeginNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java index 8fe812f285d..afceaf35f59 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.nodes; import java.util.List; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.NodeClass; import jdk.vm.ci.meta.Assumptions; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java index 68d809e49d5..4a01286f483 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.nodes; import jdk.vm.ci.meta.JavaKind.FormatWithToString; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.ResolvedJavaField; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java index 322f064628b..70c3d341709 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java @@ -37,9 +37,9 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.util.TypeReader; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java index bbbb968f10c..decbe6ccdfe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java @@ -27,8 +27,8 @@ import java.util.Deque; import java.util.Iterator; import java.util.Objects; -import org.graalvm.collections.Pair; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.Pair; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.util.FrequencyEncoder; import org.graalvm.compiler.core.common.util.TypeConversion; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphSpeculationLog.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphSpeculationLog.java new file mode 100644 index 00000000000..8d58a17c1a4 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphSpeculationLog.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes; + +import jdk.internal.vm.compiler.collections.EconomicMap; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.SpeculationLog; + +/** + * A wrapper around a {@link SpeculationLog} instance. + * + * This should be used when the wrapped instance may be accessed by multiple threads. Due to races, + * such an instance can return true for a call to {@link SpeculationLog#maySpeculate} but still fail + * (i.e. raise an {@link IllegalArgumentException}) when {@link SpeculationLog#speculate} is called. + * + * A {@link GraphSpeculationLog} must only be used by a single thread and is typically closely + * coupled with a {@link StructuredGraph} (hence the name). + */ +public final class GraphSpeculationLog implements SpeculationLog { + + private final SpeculationLog log; + private final EconomicMap speculations; + + public GraphSpeculationLog(SpeculationLog log) { + this.log = log; + this.speculations = EconomicMap.create(); + } + + /** + * Unwraps {@code log} if it is a {@link GraphSpeculationLog}. + */ + public static SpeculationLog unwrap(SpeculationLog log) { + if (log instanceof GraphSpeculationLog) { + return ((GraphSpeculationLog) log).log; + } + return log; + } + + /** + * Determines if the compiler is allowed to speculate with {@code reason}. Note that a + * {@code true} return value guarantees that a subsequent call to + * {@link #speculate(SpeculationReason)} with an argument {@linkplain Object#equals(Object) + * equal} to {@code reason} will succeed. + */ + @Override + public boolean maySpeculate(SpeculationReason reason) { + JavaConstant speculation = speculations.get(reason); + if (speculation == null) { + if (log.maySpeculate(reason)) { + try { + speculation = log.speculate(reason); + speculations.put(reason, speculation); + } catch (IllegalArgumentException e) { + // The speculation was disabled by another thread in between + // the call to log.maySpeculate and log.speculate + speculation = null; + } + } + } + return speculation != null; + } + + @Override + public JavaConstant speculate(SpeculationReason reason) { + if (maySpeculate(reason)) { + JavaConstant speculation = speculations.get(reason); + assert speculation != null; + return speculation; + } + throw new IllegalArgumentException("Cannot make speculation with reason " + reason + " as it is known to fail"); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GraphSpeculationLog) { + GraphSpeculationLog that = (GraphSpeculationLog) obj; + return this.log == that.log; + } + return false; + } + + @Override + public int hashCode() { + return log.hashCode(); + } + + @Override + public void collectFailedSpeculations() { + log.collectFailedSpeculations(); + } + + /** + * Returns if this log has speculations. + * + * @return true if {@link #maySpeculate(SpeculationReason)} has ever returned {@code true} for + * this object + */ + @Override + public boolean hasSpeculations() { + return !speculations.isEmpty(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java index 9a6dc659fbd..d3281072e94 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java @@ -30,8 +30,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java index a9789b1344e..b3a0301679a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java @@ -24,14 +24,12 @@ package org.graalvm.compiler.nodes; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; -import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.compiler.core.common.GraalOptions; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.options.OptionValues; import java.util.ArrayList; import java.util.List; @@ -56,6 +54,8 @@ import java.util.function.BiConsumer; * {@link #addDecision} to log negative decisions. */ public class InliningLog { + private static final String TREE_NODE = "\u251c\u2500\u2500"; + private static final String LAST_TREE_NODE = "\u2514\u2500\u2500"; public static final class Decision { private final boolean positive; @@ -88,7 +88,8 @@ public class InliningLog { @Override public String toString() { - return String.format("<%s> %s: %s", phase, target != null ? target.format("%H.%n(%p)") : "", reason); + return String.format("<%s> %s: %s, %s", phase, target != null ? target.format("%H.%n(%p)") : "", positive ? "yes" : "no", + reason); } } @@ -114,9 +115,9 @@ public class InliningLog { public String positionString() { if (parent == null) { - return ""; + return "compilation of " + target.format("%H.%n(%p)"); } - return MetaUtil.appendLocation(new StringBuilder(100), parent.target, getBci()).toString(); + return "at " + MetaUtil.appendLocation(new StringBuilder(100), parent.target, getBci()).toString(); } public int getBci() { @@ -126,13 +127,13 @@ public class InliningLog { private final Callsite root; private final EconomicMap leaves; - private final OptionValues options; + private final boolean enabled; - public InliningLog(ResolvedJavaMethod rootMethod, OptionValues options) { + public InliningLog(ResolvedJavaMethod rootMethod, boolean enabled) { this.root = new Callsite(null, null); this.root.target = rootMethod; this.leaves = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE); - this.options = options; + this.enabled = enabled; } /** @@ -142,15 +143,22 @@ public class InliningLog { * logged after replacing an {@link Invoke} with a graph. In this case, the node replacement map * and the {@link InliningLog} of the inlined graph must be provided. */ - public void addDecision(Invokable invoke, boolean positive, String reason, String phase, EconomicMap replacements, InliningLog calleeLog) { + public void addDecision(Invokable invoke, boolean positive, String phase, EconomicMap replacements, InliningLog calleeLog, String reason, Object... args) { + if (!enabled) { + return; + } assert leaves.containsKey(invoke); - assert (!positive && replacements == null && calleeLog == null) || (positive && replacements != null && calleeLog != null); + assert (!positive && replacements == null && calleeLog == null) || (positive && replacements != null && calleeLog != null) || + (positive && replacements == null && calleeLog == null); Callsite callsite = leaves.get(invoke); callsite.target = callsite.invoke.getTargetMethod(); - Decision decision = new Decision(positive, reason, phase, invoke.getTargetMethod()); + Decision decision = new Decision(positive, String.format(reason, args), phase, invoke.getTargetMethod()); callsite.decisions.add(decision); if (positive) { leaves.removeKey(invoke); + if (calleeLog == null) { + return; + } EconomicMap mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE); for (Callsite calleeChild : calleeLog.root.children) { Callsite child = callsite.addChild(calleeChild.invoke); @@ -227,7 +235,7 @@ public class InliningLog { mapping.put(replacementSite, site); site.target = replacementSite.target; site.decisions.addAll(replacementSite.decisions); - site.invoke = replacementSite.invoke != null && replacementSite.invoke.asFixedNode().isAlive() ? (Invokable) replacements.get(replacementSite.invoke.asFixedNode()) : null; + site.invoke = replacementSite.invoke != null && replacementSite.invoke.isAlive() ? (Invokable) replacements.get(replacementSite.invoke.asFixedNode()) : null; for (Callsite replacementChild : replacementSite.children) { Callsite child = new Callsite(site, null); site.children.add(child); @@ -253,7 +261,7 @@ public class InliningLog { private UpdateScope noUpdates = new UpdateScope((oldNode, newNode) -> { }); - private UpdateScope activated = null; + private UpdateScope currentUpdateScope = null; /** * Used to designate scopes in which {@link Invokable} registration or cloning should be handled @@ -267,17 +275,17 @@ public class InliningLog { } public void activate() { - if (activated != null) { + if (currentUpdateScope != null) { throw GraalError.shouldNotReachHere("InliningLog updating already set."); } - activated = this; + currentUpdateScope = this; } @Override public void close() { - if (GraalOptions.TraceInlining.getValue(options)) { - assert activated != null; - activated = null; + if (enabled) { + assert currentUpdateScope != null; + currentUpdateScope = null; } } @@ -287,10 +295,10 @@ public class InliningLog { } public BiConsumer getUpdateScope() { - if (activated == null) { + if (currentUpdateScope == null) { return null; } - return activated.getUpdater(); + return currentUpdateScope.getUpdater(); } /** @@ -305,7 +313,7 @@ public class InliningLog { * @return a bound {@link UpdateScope} object, or a {@code null} if tracing is disabled */ public UpdateScope openUpdateScope(BiConsumer updater) { - if (GraalOptions.TraceInlining.getValue(options)) { + if (enabled) { UpdateScope scope = new UpdateScope(updater); scope.activate(); return scope; @@ -324,7 +332,7 @@ public class InliningLog { * @see #openUpdateScope */ public UpdateScope openDefaultUpdateScope() { - if (GraalOptions.TraceInlining.getValue(options)) { + if (enabled) { noUpdates.activate(); return noUpdates; } else { @@ -332,6 +340,97 @@ public class InliningLog { } } + private RootScope currentRootScope = null; + + /** + * Used to change the current effective root of the method being compiled. + * + * This root scope is used in situations in which a phase does its own ad-hoc inlining, in which + * it replaces an Invoke with other nodes, some of which may be other Invokes. The prime example + * for this is the bytecode parser, which does not create separate graphs with their own + * inlining logs when inlining an Invoke, but instead continues recursively parsing the graph + * corresponding to the Invoke. + * + * Root scopes can be nested. + * + * @see #openRootScope + */ + public final class RootScope implements AutoCloseable { + private final RootScope parent; + private Callsite replacementRoot; + + public RootScope(RootScope parent, Callsite replacementRoot) { + this.parent = parent; + this.replacementRoot = replacementRoot; + } + + void activate() { + currentRootScope = this; + } + + public Invokable getInvoke() { + return replacementRoot.invoke; + } + + @Override + public void close() { + if (enabled) { + assert currentRootScope != null; + removeLeafCallsite(replacementRoot.invoke); + currentRootScope = parent; + } + } + } + + public final class PlaceholderInvokable implements Invokable { + private int bci; + private ResolvedJavaMethod method; + + public PlaceholderInvokable(ResolvedJavaMethod method, int bci) { + this.method = method; + this.bci = bci; + } + + @Override + public ResolvedJavaMethod getTargetMethod() { + return method; + } + + @Override + public int bci() { + return bci; + } + + @Override + public boolean isAlive() { + return false; + } + + @Override + public FixedNode asFixedNode() { + throw new UnsupportedOperationException("Parsed invokable is a placeholder, not a concrete node."); + } + } + + public RootScope openRootScope(ResolvedJavaMethod target, int bci) { + return openRootScope(new PlaceholderInvokable(target, bci)); + } + + public RootScope openRootScope(Invokable invoke) { + if (enabled) { + if (!leaves.containsKey(invoke)) { + // Create the invoke if it was not added to the graph yet. + trackNewCallsite(invoke); + } + RootScope scope = new RootScope(currentRootScope, leaves.get(invoke)); + scope.replacementRoot.target = invoke.getTargetMethod(); + scope.activate(); + return scope; + } else { + return null; + } + } + public boolean containsLeafCallsite(Invokable invokable) { return leaves.containsKey(invokable); } @@ -342,11 +441,16 @@ public class InliningLog { public void trackNewCallsite(Invokable invoke) { assert !leaves.containsKey(invoke); - Callsite callsite = new Callsite(root, invoke); - root.children.add(callsite); + Callsite currentRoot = findCurrentRoot(); + Callsite callsite = new Callsite(currentRoot, invoke); + currentRoot.children.add(callsite); leaves.put(invoke, callsite); } + private Callsite findCurrentRoot() { + return currentRootScope != null ? currentRootScope.replacementRoot : root; + } + public void trackDuplicatedCallsite(Invokable sibling, Invokable newInvoke) { Callsite siblingCallsite = leaves.get(sibling); Callsite parentCallsite = siblingCallsite.parent; @@ -361,7 +465,19 @@ public class InliningLog { callsite.invoke = newInvoke; } - public String formatAsTree() { + /** + * Formats the inlining log as a hierarchical tree. + * + * @param nullIfEmpty specifies whether null should be returned if there are no inlining + * decisions + * @return the tree representation of the inlining log + */ + public String formatAsTree(boolean nullIfEmpty) { + assert root.decisions.isEmpty(); + assert !root.children.isEmpty() || leaves.isEmpty(); + if (nullIfEmpty && root.children.isEmpty()) { + return null; + } StringBuilder builder = new StringBuilder(512); formatAsTree(root, "", builder); return builder.toString(); @@ -369,12 +485,20 @@ public class InliningLog { private void formatAsTree(Callsite site, String indent, StringBuilder builder) { String position = site.positionString(); - builder.append(indent).append("at ").append(position).append(": "); + builder.append(indent).append(position).append(": "); if (site.decisions.isEmpty()) { + if (site.parent != null) { + builder.append("(no decisions made about ").append(site.target != null ? site.target.format("%H.%n(%p)") : "").append(")"); + } + builder.append(System.lineSeparator()); + } else if (site.decisions.size() == 1) { + builder.append(site.decisions.get(0).toString()); builder.append(System.lineSeparator()); } else { + builder.append(System.lineSeparator()); for (Decision decision : site.decisions) { - builder.append(decision.toString()); + String node = (decision == site.decisions.get(site.decisions.size() - 1)) ? LAST_TREE_NODE : TREE_NODE; + builder.append(indent + " " + node).append(decision.toString()); builder.append(System.lineSeparator()); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java index a98f34f009b..0852b69c385 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java @@ -35,6 +35,10 @@ public interface Invokable { int bci(); + default boolean isAlive() { + return asFixedNode().isAlive(); + } + FixedNode asFixedNode(); /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java index 09020c405d3..386a842b9e2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java @@ -41,7 +41,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import java.util.Map; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java index 5ba791a7e45..9487437d750 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java @@ -37,7 +37,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import java.util.Map; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java index bff55ca7589..b45c59ebf93 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java @@ -29,7 +29,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_0, size = SIZE_0) public final class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java index b72645fa8bc..460ea9a2a09 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java @@ -105,9 +105,7 @@ public final class LoopExitNode extends BeginStateSplitNode implements IterableN Node prev = this.predecessor(); while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) { AbstractBeginNode begin = (AbstractBeginNode) prev; - if (begin.getNodeSourcePosition() != null || this.getNodeSourcePosition() == null || this.getNodeSourcePosition().isPlaceholder()) { - this.setNodeSourcePosition(begin.getNodeSourcePosition()); - } + this.setNodeSourcePosition(begin.getNodeSourcePosition()); prev = prev.predecessor(); graph().removeFixed(begin); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java index b212a390348..c2360606378 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java @@ -24,9 +24,9 @@ package org.graalvm.compiler.nodes; import java.util.EnumMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaKind.FormatWithToString; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java index edd89e638a1..1423c2ec4ff 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java @@ -29,7 +29,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * The start node of a graph. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java index 93489ed3ee5..f31cb5b55d7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java @@ -30,10 +30,10 @@ import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.core.common.CancellationBailoutException; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.GraalOptions; @@ -359,12 +359,16 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { this.compilationId = compilationId; this.entryBCI = entryBCI; this.assumptions = assumptions; - this.speculationLog = speculationLog; + if (speculationLog != null && !(speculationLog instanceof GraphSpeculationLog)) { + this.speculationLog = new GraphSpeculationLog(speculationLog); + } else { + this.speculationLog = speculationLog; + } this.useProfilingInfo = useProfilingInfo; this.trackNodeSourcePosition = trackNodeSourcePosition; assert trackNodeSourcePosition != null; this.cancellable = cancellable; - this.inliningLog = new InliningLog(rootMethod, options); + this.inliningLog = new InliningLog(rootMethod, GraalOptions.TraceInlining.getValue(options)); this.callerContext = context; } @@ -480,7 +484,10 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { public void logInliningTree() { if (GraalOptions.TraceInlining.getValue(getOptions())) { - TTY.println(getInliningLog().formatAsTree()); + String formattedTree = getInliningLog().formatAsTree(true); + if (formattedTree != null) { + TTY.println(formattedTree); + } } } @@ -518,6 +525,7 @@ public final class StructuredGraph extends Graph implements JavaMethodContext { copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase; copy.hasValueProxies = hasValueProxies; copy.isAfterExpandLogic = isAfterExpandLogic; + copy.trackNodeSourcePosition = trackNodeSourcePosition; EconomicMap replacements = EconomicMap.create(Equivalence.IDENTITY); replacements.put(start, copy.start); UnmodifiableEconomicMap duplicates; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java index fdfc4719a26..2540a7f2200 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java @@ -39,7 +39,7 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public final class Block extends AbstractBlockBase { public static final Block[] EMPTY_ARRAY = new Block[0]; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java index 0fafc0c6c17..273801d30b9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.nodes.cfg; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.nodes.LoopBeginNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public final class HIRLoop extends Loop { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java index c3fbd5fae38..01352113d2d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java @@ -26,7 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public class LocationSet { private LocationIdentity firstLocation; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java index c19d8c1d3f4..47b4dbf51b2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java index 2c1b8fe0309..93a842ea1c1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java @@ -37,7 +37,7 @@ import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.MetaAccessProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java index 348b5aec4ff..bf272c0d226 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java @@ -46,7 +46,7 @@ import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java index 18d5c2244ce..43d7075e401 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java @@ -27,7 +27,7 @@ import static org.graalvm.compiler.nodeinfo.InputType.Guard; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java index a247a0b4409..b99440774d1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java index c5d677fa14a..d3ed3536a03 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java index e1f94765ba2..418de48470b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java @@ -33,7 +33,7 @@ import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Creates a memory barrier. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java index 39db72a6859..9a553f09f4a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java @@ -44,7 +44,7 @@ import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.Constant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java index 69503e6c12c..b9c0d638a8d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java @@ -39,7 +39,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java index f45dc8f89e8..b6dccdf60ce 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java @@ -35,7 +35,7 @@ import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.type.StampTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java index af29cf1e595..fea137c383f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java @@ -26,7 +26,7 @@ import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java index d7be0f7e6e4..4dd70f4b0bd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java index 1dc6c885518..1dfe4f8c428 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java @@ -33,7 +33,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java index 1b97ce00b20..087061d0440 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java @@ -35,15 +35,16 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; -import org.graalvm.collections.Pair; -import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.collections.Pair; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry; import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -862,6 +863,7 @@ public class InvocationPlugins { lateRegistrations = lateClassPlugins; } + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "string literal object identity used as sentinel") private synchronized boolean closeLateRegistrations() { if (lateRegistrations == null || lateRegistrations.className != CLOSED_LATE_CLASS_PLUGIN) { lateRegistrations = new LateClassPlugins(lateRegistrations, CLOSED_LATE_CLASS_PLUGIN); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java index 332c51053ed..a102eaaa292 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java @@ -37,7 +37,7 @@ import org.graalvm.compiler.nodes.memory.FixedAccessNode; import org.graalvm.compiler.nodes.memory.LIRLowerableAccess; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Low-level atomic compare-and-swap operation. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java index 702b1c2d638..8bdb6b771ae 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java index 72da5220750..a73225b9a9c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java @@ -33,7 +33,7 @@ import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java index c00e7e842f5..f797750e5f8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java @@ -39,7 +39,7 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import static org.graalvm.compiler.nodeinfo.InputType.Memory; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java index 8cc692a0d7d..d0509948969 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java index 6bb19da8359..e184526f244 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java @@ -39,7 +39,7 @@ import org.graalvm.compiler.nodes.memory.LIRLowerableAccess; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java index 042bc93a5d2..c6a814649ac 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java index b3eb8fcbb36..0b899f524d8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * The {@code MonitorExitNode} represents a monitor release. If it is the release of the monitor of diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java index 9870bbb9994..87e0a75344f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java @@ -38,7 +38,7 @@ import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * The {@code RawMonitorEnterNode} represents the acquisition of a monitor. The object needs to diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java index 4bbdb302829..345c23897bf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; @@ -53,8 +53,8 @@ public final class UnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint imp @Input ValueNode expected; @Input ValueNode newValue; - protected final JavaKind valueKind; - protected final LocationIdentity locationIdentity; + private final JavaKind valueKind; + private final LocationIdentity locationIdentity; public UnsafeCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind valueKind, LocationIdentity locationIdentity) { super(TYPE, StampFactory.forKind(JavaKind.Boolean.getStackKind())); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java index 5125954d93c..d232b716c2d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * A special purpose store node that differs from {@link LogicCompareAndSwapNode} in that it returns diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java index 19569e021bc..bf46d2d418c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValueNodeUtil; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; @NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Guard}, cycles = CYCLES_2, size = SIZE_1) public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java index f277b0ad1f0..d4e795c2273 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.nodes.memory; import org.graalvm.compiler.nodes.extended.GuardedNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public interface Access extends GuardedNode, HeapAccess { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java index 9df482b446b..7dcb1573172 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java @@ -31,7 +31,7 @@ import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Accesses a value at an memory address specified by an {@linkplain #address address}. The access diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java index 70a13aa25f9..9aa28fc9942 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java @@ -28,7 +28,7 @@ import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java index 43dd02ca8d3..c1a6e17eeed 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java @@ -29,7 +29,7 @@ import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.FloatingGuardedNode; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; @NodeInfo public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java index 40dc67fd9a6..5e4d2cef9b7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java @@ -41,7 +41,7 @@ import org.graalvm.compiler.nodes.ValuePhiNode; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * A floating read of a value from memory specified in terms of an object base and an object diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java index 8b07251b5c1..e6c182b6e08 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.nodes.memory; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * This interface marks nodes that access some memory location, and that have an edge to the last diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java index b8dad8fd6a1..348172b3339 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.nodes.memory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedNodeInterface; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * This interface marks subclasses of {@link FixedNode} that kill a set of memory locations diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java index 95d7a16a2a8..14a7a566880 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.nodes.memory; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java index ac72a1690cf..e619e5403d5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java @@ -26,15 +26,15 @@ import static org.graalvm.compiler.nodeinfo.InputType.Extension; import static org.graalvm.compiler.nodeinfo.InputType.Memory; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeInputList; @@ -44,7 +44,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; @NodeInfo(allowedUsageTypes = {Extension, Memory}, cycles = CYCLES_0, size = SIZE_0) public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java index 5e7f2a30819..d504633f9d5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java @@ -30,7 +30,7 @@ import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Memory {@code PhiNode}s merge memory dependencies at control flow merges. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java index fbe26e2653f..701e43c3935 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java @@ -48,7 +48,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.MetaAccessProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java index a2ecb533fd8..2b05bf869f5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java @@ -33,7 +33,7 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java index 98aa49f19a6..af5f3349c0b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java @@ -23,7 +23,7 @@ package org.graalvm.compiler.nodes.spi; import org.graalvm.compiler.nodes.memory.MemoryNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public interface MemoryProxy extends Proxy, MemoryNode { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java index 959e252567b..65dace3dc80 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java @@ -30,10 +30,10 @@ import java.util.Iterator; import java.util.List; import java.util.function.BiFunction; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.code.SourceStackTraceBailoutException; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java index 222dd1d7ed4..5b246faf34e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java @@ -54,7 +54,7 @@ import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; import org.graalvm.compiler.nodes.spi.VirtualizerTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; // @formatter:off @NodeInfo(nameTemplate = "Alloc {i#virtualObjects}", diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java index 797a127bbf6..b3b5c274c87 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java @@ -61,6 +61,7 @@ import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; /** * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors} @@ -218,7 +219,7 @@ public class OptionProcessor extends AbstractProcessor { } } - info.options.add(new OptionInfo(optionName, help, extraHelp, optionType, declaringClass, field)); + info.options.add(new OptionInfo(optionName, annotation.type(), help, extraHelp, optionType, declaringClass, field)); } private void createFiles(OptionsInfo info) { @@ -243,6 +244,7 @@ public class OptionProcessor extends AbstractProcessor { out.println(""); out.println("import java.util.*;"); out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;"); + out.println("import " + OptionType.class.getName() + ";"); out.println(""); out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {"); @@ -263,6 +265,7 @@ public class OptionProcessor extends AbstractProcessor { optionField = option.declaringClass + "." + option.field.getSimpleName(); } out.println(" case \"" + name + "\": {"); + OptionType optionType = option.optionType; String type = option.type; String help = option.help; String[] extraHelp = option.extraHelp; @@ -270,7 +273,8 @@ public class OptionProcessor extends AbstractProcessor { Name fieldName = option.field.getSimpleName(); out.printf(" return " + desc + ".create(\n"); out.printf(" /*name*/ \"%s\",\n", name); - out.printf(" /*type*/ %s.class,\n", type); + out.printf(" /*optionType*/ %s.%s,\n", optionType.getDeclaringClass().getSimpleName(), optionType.name()); + out.printf(" /*optionValueType*/ %s.class,\n", type); out.printf(" /*help*/ \"%s\",\n", help); if (extraHelp.length != 0) { out.printf(" /*extraHelp*/ new String[] {\n"); @@ -332,14 +336,16 @@ public class OptionProcessor extends AbstractProcessor { static class OptionInfo implements Comparable { final String name; + final OptionType optionType; final String help; final String[] extraHelp; final String type; final String declaringClass; final VariableElement field; - OptionInfo(String name, String help, String[] extraHelp, String type, String declaringClass, VariableElement field) { + OptionInfo(String name, OptionType optionType, String help, String[] extraHelp, String type, String declaringClass, VariableElement field) { this.name = name; + this.optionType = optionType; this.help = help; this.extraHelp = extraHelp; this.type = type; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionKeyTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionKeyTest.java index 242d3396a18..18d7320d6fc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionKeyTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/NestedBooleanOptionKeyTest.java @@ -40,6 +40,7 @@ import static org.junit.Assert.assertTrue; import org.graalvm.compiler.options.NestedBooleanOptionKey; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.junit.Test; @@ -54,12 +55,12 @@ public class NestedBooleanOptionKeyTest { public static final OptionKey NestedOption2 = new NestedBooleanOptionKey(Master2, false); } - static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0); - static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0); - static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1); - static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1); - static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2); - static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2); + static final OptionDescriptor master0 = OptionDescriptor.create("Master0", OptionType.Debug, Boolean.class, "", Options.class, "Master0", Master0); + static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", OptionType.Debug, Boolean.class, "", Options.class, "NestedOption0", NestedOption0); + static final OptionDescriptor master1 = OptionDescriptor.create("Master1", OptionType.Debug, Boolean.class, "", Options.class, "Master1", Master1); + static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", OptionType.Debug, Boolean.class, "", Options.class, "NestedOption1", NestedOption1); + static final OptionDescriptor master2 = OptionDescriptor.create("Master2", OptionType.Debug, Boolean.class, "", Options.class, "Master2", Master2); + static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", OptionType.Debug, Boolean.class, "", Options.class, "NestedOption2", NestedOption2); @Test public void runDefaultTrue() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java index e090647baf1..5dc95fbe920 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.test/src/org/graalvm/compiler/options/test/TestOptionKey.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertEquals; import org.graalvm.compiler.options.ModifiableOptionValues; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.junit.Assert; import org.junit.Assume; @@ -51,7 +52,7 @@ public class TestOptionKey { @Test public void toStringTest() { - OptionDescriptor.create("MyOption", String.class, "", Options.class, "MyOption", MyOption); + OptionDescriptor.create("MyOption", OptionType.Debug, String.class, "", Options.class, "MyOption", MyOption); assertEquals("MyOption", MyOption.toString()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java index 226dc49cf79..e2422312f03 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.options; import java.util.EnumSet; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; public class EnumOptionKey> extends OptionKey { final Class enumClass; @@ -45,11 +45,11 @@ public class EnumOptionKey> extends OptionKey { return EnumSet.allOf(enumClass); } - Object valueOf(String name) { + public Object valueOf(String name) { try { return Enum.valueOf(enumClass, name); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("\"" + name + "\" is not a valid option for " + getName() + ". Valid values are " + EnumSet.allOf(enumClass)); + throw new IllegalArgumentException("\"" + name + "\" is not a valid option for " + getName() + ". Valid values are " + getAllValues()); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java index 38bc3622d44..85c5debd6af 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java @@ -24,10 +24,10 @@ package org.graalvm.compiler.options; import java.util.concurrent.atomic.AtomicReference; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; /** * A context for obtaining values for {@link OptionKey}s that allows for key/value pairs to be diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java index b70db410294..b538c0d2738 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionDescriptor.java @@ -33,7 +33,8 @@ import java.util.List; public final class OptionDescriptor { protected final String name; - protected final Class type; + protected final OptionType optionType; + protected final Class optionValueType; protected final String help; protected final List extraHelp; protected final OptionKey optionKey; @@ -42,39 +43,41 @@ public final class OptionDescriptor { private static final String[] NO_EXTRA_HELP = {}; - public static OptionDescriptor create(String name, Class type, String help, Class declaringClass, String fieldName, OptionKey option) { - return create(name, type, help, NO_EXTRA_HELP, declaringClass, fieldName, option); + public static OptionDescriptor create(String name, OptionType optionType, Class optionValueType, String help, Class declaringClass, String fieldName, OptionKey option) { + return create(name, optionType, optionValueType, help, NO_EXTRA_HELP, declaringClass, fieldName, option); } - public static OptionDescriptor create(String name, Class type, String help, String[] extraHelp, Class declaringClass, String fieldName, OptionKey option) { + public static OptionDescriptor create(String name, OptionType optionType, Class optionValueType, String help, String[] extraHelp, Class declaringClass, String fieldName, + OptionKey option) { assert option != null : declaringClass + "." + fieldName; OptionDescriptor result = option.getDescriptor(); if (result == null) { List extraHelpList = extraHelp == null || extraHelp.length == 0 ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(extraHelp)); - result = new OptionDescriptor(name, type, help, extraHelpList, declaringClass, fieldName, option); + result = new OptionDescriptor(name, optionType, optionValueType, help, extraHelpList, declaringClass, fieldName, option); option.setDescriptor(result); } - assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.optionKey == option; + assert result.name.equals(name) && result.optionValueType == optionValueType && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.optionKey == option; return result; } - private OptionDescriptor(String name, Class type, String help, List extraHelp, Class declaringClass, String fieldName, OptionKey optionKey) { + private OptionDescriptor(String name, OptionType optionType, Class optionValueType, String help, List extraHelp, Class declaringClass, String fieldName, OptionKey optionKey) { this.name = name; - this.type = type; + this.optionType = optionType; + this.optionValueType = optionValueType; this.help = help; this.extraHelp = extraHelp; this.optionKey = optionKey; this.declaringClass = declaringClass; this.fieldName = fieldName; - assert !type.isPrimitive() : "must used boxed type instead of " + type; + assert !optionValueType.isPrimitive() : "must used boxed optionValueType instead of " + optionValueType; } /** * Gets the type of values stored in the option. This will be the boxed type for a primitive * option. */ - public Class getType() { - return type; + public Class getOptionValueType() { + return optionValueType; } /** @@ -103,6 +106,13 @@ public final class OptionDescriptor { return name; } + /** + * Gets the type of the option. + */ + public OptionType getOptionType() { + return optionType; + } + /** * Gets the boxed option value. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java index 76baa5a40f8..a20e198d6e4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.options; import java.util.Formatter; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; /** * A key for an option. The value for an option is obtained from an {@link OptionValues} object. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java index 5ec5cf4c831..14ee4e27152 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java @@ -30,10 +30,10 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; /** * A context for obtaining values for {@link OptionKey}s. @@ -126,7 +126,7 @@ public class OptionValues { /** * Decodes a value that may be the sentinel value for {@code null} in a map. */ - protected static Object decodeNull(Object value) { + public static Object decodeNull(Object value) { return value == NULL ? null : value; } @@ -212,7 +212,7 @@ public class OptionValues { String name = namePrefix + e.getKey(); String assign = containsKey(desc.optionKey) ? ":=" : "="; - String typeName = desc.getOptionKey() instanceof EnumOptionKey ? "String" : desc.getType().getSimpleName(); + String typeName = desc.getOptionKey() instanceof EnumOptionKey ? "String" : desc.getOptionValueType().getSimpleName(); String linePrefix = String.format("%s %s %s ", name, assign, value); int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length(); int linePad = typeStartPos - linePrefix.length(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java index 1cb4a607ef4..c5006ae5939 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java @@ -28,8 +28,8 @@ import java.util.Formatter; import java.util.List; import java.util.ServiceLoader; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.util.CollectionsUtil; /** @@ -116,7 +116,7 @@ public class OptionsParser { * @param loader source of the available {@link OptionDescriptors} * @throws IllegalArgumentException if there's a problem parsing {@code option} */ - static void parseOption(String name, Object uncheckedValue, EconomicMap, Object> values, Iterable loader) { + public static void parseOption(String name, Object uncheckedValue, EconomicMap, Object> values, Iterable loader) { OptionDescriptor desc = lookup(loader, name); if (desc == null) { @@ -132,7 +132,7 @@ public class OptionsParser { throw new IllegalArgumentException(msg.toString()); } - Class optionType = desc.getType(); + Class optionType = desc.getOptionValueType(); Object value; if (!(uncheckedValue instanceof String)) { if (optionType != uncheckedValue.getClass()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringByUsePhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringByUsePhase.java index 6c7f3c8ce15..b8fa84374f2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringByUsePhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringByUsePhase.java @@ -93,7 +93,7 @@ public class AddressLoweringByUsePhase extends Phase { } else { continue; } - // the lowered address amy already be a replacement + // the lowered address may already be a replacement // in which case we want to use it not delete it! if (lowered != address) { // replace original with lowered at this usage only diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java index 957984e2242..8e5920fd3a2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java @@ -314,7 +314,7 @@ public class CanonicalizerPhase extends BasePhase { @SuppressWarnings("try") public boolean tryCanonicalize(final Node node, NodeClass nodeClass) { - try (DebugCloseable position = node.withNodeSourcePosition()) { + try (DebugCloseable position = node.withNodeSourcePosition(); DebugContext.Scope scope = debug.scope("tryCanonicalize", node)) { if (customCanonicalizer != null) { Node canonical = customCanonicalizer.canonicalize(node); if (performReplacement(node, canonical)) { @@ -349,6 +349,8 @@ public class CanonicalizerPhase extends BasePhase { return node.isDeleted(); } return false; + } catch (Throwable throwable) { + throw debug.handle(throwable); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java index 9e5db5ae96c..20ade649751 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java @@ -28,10 +28,10 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java index 889c11cb67e..39554260739 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java @@ -24,6 +24,7 @@ package org.graalvm.compiler.phases.common; import org.graalvm.compiler.core.common.type.FloatStamp; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; @@ -51,6 +52,7 @@ public class ExpandLogicPhase extends Phase { private static final double EPSILON = 1E-6; @Override + @SuppressWarnings("try") protected void run(StructuredGraph graph) { for (ShortCircuitOrNode logic : graph.getNodes(ShortCircuitOrNode.TYPE)) { processBinary(logic); @@ -58,7 +60,9 @@ public class ExpandLogicPhase extends Phase { assert graph.getNodes(ShortCircuitOrNode.TYPE).isEmpty(); for (NormalizeCompareNode logic : graph.getNodes(NormalizeCompareNode.TYPE)) { - processNormalizeCompareNode(logic); + try (DebugCloseable context = logic.withNodeSourcePosition()) { + processNormalizeCompareNode(logic); + } } graph.setAfterExpandLogic(); } @@ -84,76 +88,83 @@ public class ExpandLogicPhase extends Phase { normalize.replaceAtUsagesAndDelete(value); } + @SuppressWarnings("try") private static void processBinary(ShortCircuitOrNode binary) { while (binary.usages().isNotEmpty()) { Node usage = binary.usages().first(); - if (usage instanceof ShortCircuitOrNode) { - processBinary((ShortCircuitOrNode) usage); - } else if (usage instanceof IfNode) { - processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, binary.getShortCircuitProbability()); - } else if (usage instanceof ConditionalNode) { - processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage); - } else { - throw GraalError.shouldNotReachHere(); + try (DebugCloseable nsp = usage.withNodeSourcePosition()) { + if (usage instanceof ShortCircuitOrNode) { + processBinary((ShortCircuitOrNode) usage); + } else if (usage instanceof IfNode) { + processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, binary.getShortCircuitProbability()); + } else if (usage instanceof ConditionalNode) { + processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage); + } else { + throw GraalError.shouldNotReachHere(); + } } } binary.safeDelete(); } + @SuppressWarnings("try") private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) { - /* - * this method splits an IfNode, which has a ShortCircuitOrNode as its condition, into two - * separate IfNodes: if(X) and if(Y) - * - * for computing the probabilities P(X) and P(Y), we use two different approaches. The first - * one assumes that the shortCircuitProbability and the probability on the IfNode were - * created with each other in mind. If this assumption does not hold, we fall back to - * another mechanism for computing the probabilities. - */ - AbstractBeginNode trueTarget = ifNode.trueSuccessor(); - AbstractBeginNode falseTarget = ifNode.falseSuccessor(); - - // 1st approach - // assumption: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y)) - double firstIfTrueProbability = shortCircuitProbability; - double secondIfTrueProbability = sanitizeProbability((ifNode.getTrueSuccessorProbability() - shortCircuitProbability) / (1 - shortCircuitProbability)); - double expectedOriginalIfTrueProbability = firstIfTrueProbability + (1 - firstIfTrueProbability) * secondIfTrueProbability; - - if (!doubleEquals(ifNode.getTrueSuccessorProbability(), expectedOriginalIfTrueProbability)) { + try (DebugCloseable context = ifNode.withNodeSourcePosition()) { /* - * 2nd approach + * this method splits an IfNode, which has a ShortCircuitOrNode as its condition, into + * two separate IfNodes: if(X) and if(Y) * - * the assumption above did not hold, so we either used an artificial probability as - * shortCircuitProbability or the ShortCircuitOrNode was moved to some other IfNode. - * - * so, we distribute the if's trueSuccessorProbability between the newly generated if - * nodes according to the shortCircuitProbability. the following invariant is always - * true in this case: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y)) + * for computing the probabilities P(X) and P(Y), we use two different approaches. The + * first one assumes that the shortCircuitProbability and the probability on the IfNode + * were created with each other in mind. If this assumption does not hold, we fall back + * to another mechanism for computing the probabilities. */ - firstIfTrueProbability = ifNode.getTrueSuccessorProbability() * shortCircuitProbability; - secondIfTrueProbability = sanitizeProbability(1 - (ifNode.probability(falseTarget) / (1 - firstIfTrueProbability))); - } + AbstractBeginNode trueTarget = ifNode.trueSuccessor(); + AbstractBeginNode falseTarget = ifNode.falseSuccessor(); - ifNode.clearSuccessors(); - Graph graph = ifNode.graph(); - AbstractMergeNode trueTargetMerge = graph.add(new MergeNode()); - trueTargetMerge.setNext(trueTarget); - EndNode firstTrueEnd = graph.add(new EndNode()); - EndNode secondTrueEnd = graph.add(new EndNode()); - trueTargetMerge.addForwardEnd(firstTrueEnd); - trueTargetMerge.addForwardEnd(secondTrueEnd); - AbstractBeginNode firstTrueTarget = BeginNode.begin(firstTrueEnd); - AbstractBeginNode secondTrueTarget = BeginNode.begin(secondTrueEnd); - if (yNegated) { - secondIfTrueProbability = 1.0 - secondIfTrueProbability; + // 1st approach + // assumption: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y)) + double firstIfTrueProbability = shortCircuitProbability; + double secondIfTrueProbability = sanitizeProbability((ifNode.getTrueSuccessorProbability() - shortCircuitProbability) / (1 - shortCircuitProbability)); + double expectedOriginalIfTrueProbability = firstIfTrueProbability + (1 - firstIfTrueProbability) * secondIfTrueProbability; + + if (!doubleEquals(ifNode.getTrueSuccessorProbability(), expectedOriginalIfTrueProbability)) { + /* + * 2nd approach + * + * the assumption above did not hold, so we either used an artificial probability as + * shortCircuitProbability or the ShortCircuitOrNode was moved to some other IfNode. + * + * so, we distribute the if's trueSuccessorProbability between the newly generated + * if nodes according to the shortCircuitProbability. the following invariant is + * always true in this case: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * + * P(Y)) + */ + firstIfTrueProbability = ifNode.getTrueSuccessorProbability() * shortCircuitProbability; + secondIfTrueProbability = sanitizeProbability(1 - (ifNode.probability(falseTarget) / (1 - firstIfTrueProbability))); + } + + ifNode.clearSuccessors(); + Graph graph = ifNode.graph(); + AbstractMergeNode trueTargetMerge = graph.add(new MergeNode()); + trueTargetMerge.setNext(trueTarget); + EndNode firstTrueEnd = graph.add(new EndNode()); + EndNode secondTrueEnd = graph.add(new EndNode()); + trueTargetMerge.addForwardEnd(firstTrueEnd); + trueTargetMerge.addForwardEnd(secondTrueEnd); + AbstractBeginNode firstTrueTarget = BeginNode.begin(firstTrueEnd); + AbstractBeginNode secondTrueTarget = BeginNode.begin(secondTrueEnd); + if (yNegated) { + secondIfTrueProbability = 1.0 - secondIfTrueProbability; + } + if (xNegated) { + firstIfTrueProbability = 1.0 - firstIfTrueProbability; + } + AbstractBeginNode secondIf = BeginNode.begin(graph.add(new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfTrueProbability))); + IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIf : firstTrueTarget, xNegated ? firstTrueTarget : secondIf, firstIfTrueProbability)); + ifNode.replaceAtPredecessor(firstIf); + ifNode.safeDelete(); } - if (xNegated) { - firstIfTrueProbability = 1.0 - firstIfTrueProbability; - } - AbstractBeginNode secondIf = BeginNode.begin(graph.add(new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfTrueProbability))); - IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIf : firstTrueTarget, xNegated ? firstTrueTarget : secondIf, firstIfTrueProbability)); - ifNode.replaceAtPredecessor(firstIf); - ifNode.safeDelete(); } private static boolean doubleEquals(double a, double b) { @@ -169,13 +180,16 @@ public class ExpandLogicPhase extends Phase { return newValue; } + @SuppressWarnings("try") private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional) { - ValueNode trueTarget = conditional.trueValue(); - ValueNode falseTarget = conditional.falseValue(); - Graph graph = conditional.graph(); - ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget)); - ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? secondConditional : trueTarget, xNegated ? trueTarget : secondConditional)); - conditional.replaceAndDelete(firstConditional); + try (DebugCloseable context = conditional.withNodeSourcePosition()) { + ValueNode trueTarget = conditional.trueValue(); + ValueNode falseTarget = conditional.falseValue(); + Graph graph = conditional.graph(); + ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget)); + ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? secondConditional : trueTarget, xNegated ? trueTarget : secondConditional)); + conditional.replaceAndDelete(firstConditional); + } } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java index 7eaf9078d36..caa98c0640e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.phases.common; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.FloatStamp; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java index 02db5abf038..4c150217206 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java @@ -24,16 +24,16 @@ package org.graalvm.compiler.phases.common; import static org.graalvm.compiler.graph.Graph.NodeEvent.NODE_ADDED; import static org.graalvm.compiler.graph.Graph.NodeEvent.ZERO_USAGES; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.graph.Graph.NodeEventScope; @@ -71,7 +71,7 @@ import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public class FloatingReadPhase extends Phase { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java index 25e0c90c2de..98f867dd1db 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.phases.common; import java.util.List; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java index ea0c7b393ca..36a0ce840e6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java @@ -75,7 +75,7 @@ import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java index 6acd6e731a0..91630b599e5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java @@ -22,9 +22,9 @@ */ package org.graalvm.compiler.phases.common; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.graph.NodeStack; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractDeoptimizeNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java index 2cf2f0c5012..fd063d7858d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java @@ -33,11 +33,11 @@ import java.util.List; import java.util.Objects; import java.util.function.Consumer; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.core.common.GraalOptions; @@ -45,6 +45,7 @@ import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.core.common.util.Util; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.GraalGraphError; @@ -340,7 +341,13 @@ public class InliningUtil extends ValueMergeUtil { */ @SuppressWarnings("try") public static UnmodifiableEconomicMap inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) { - return inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod, "", ""); + try { + return inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod, "reason not specified", "phase not specified"); + } catch (GraalError ex) { + ex.addContext("inlining into", invoke.asNode().graph().method()); + ex.addContext("inlinee", inlineGraph.method()); + throw ex; + } } /** @@ -423,7 +430,7 @@ public class InliningUtil extends ValueMergeUtil { try (InliningLog.UpdateScope scope = graph.getInliningLog().openDefaultUpdateScope()) { duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement); if (scope != null) { - graph.getInliningLog().addDecision(invoke, true, reason, phase, duplicates, inlineGraph.getInliningLog()); + graph.getInliningLog().addDecision(invoke, true, phase, duplicates, inlineGraph.getInliningLog(), reason); } } @@ -491,13 +498,8 @@ public class InliningUtil extends ValueMergeUtil { * @return the set of nodes to canonicalize */ @SuppressWarnings("try") - public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) { - return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, null); - } - - public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, - Consumer> duplicatesConsumer) { - return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, duplicatesConsumer, "", ""); + public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, String reason, String phase) { + return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, null, reason, phase); } @SuppressWarnings("try") @@ -684,28 +686,42 @@ public class InliningUtil extends ValueMergeUtil { newNodes.addAll(invokeGraph.getNewNodes(mark)); EconomicMap posMap = EconomicMap.create(Equivalence.DEFAULT); UnmodifiableMapCursor cursor = duplicates.getEntries(); + ResolvedJavaMethod inlineeRoot = null; while (cursor.advance()) { - if (!newNodes.contains(cursor.getValue())) { + Node value = cursor.getValue(); + if (!newNodes.contains(value)) { continue; } - NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition(); - if (pos != null) { - NodeSourcePosition callerPos = posMap.get(pos); - if (callerPos == null) { - callerPos = pos.addCaller(invokePos, isSubstitution); - posMap.put(pos, callerPos); - } - cursor.getValue().setNodeSourcePosition(callerPos); + if (isSubstitution && invokePos == null) { + // There's no caller information so the source position for this node will be + // invalid, so it should be cleared. + value.clearNodeSourcePosition(); } else { - if (isSubstitution) { - /* - * If no other position is provided at least attribute the substituted node to - * the original invoke. - */ - cursor.getValue().setNodeSourcePosition(invokePos); + NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition(); + if (pos != null) { + if (inlineeRoot == null) { + assert (inlineeRoot = pos.getRootMethod()) != null; + } else { + assert pos.verifyRootMethod(inlineeRoot); + } + NodeSourcePosition callerPos = posMap.get(pos); + if (callerPos == null) { + callerPos = pos.addCaller(invokePos, isSubstitution); + posMap.put(pos, callerPos); + } + value.setNodeSourcePosition(callerPos); + } else { + if (isSubstitution) { + /* + * If no other position is provided at least attribute the substituted node + * to the original invoke. + */ + value.setNodeSourcePosition(invokePos); + } } } } + assert invokeGraph.verifySourcePositions(); } public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) { @@ -942,37 +958,42 @@ public class InliningUtil extends ValueMergeUtil { * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null, and * ensuring that the resulting type is compatible with the method being invoked. */ + @SuppressWarnings("try") public static ValueNode nonNullReceiver(Invoke invoke) { - MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); - assert !callTarget.isStatic() : callTarget.targetMethod(); - StructuredGraph graph = callTarget.graph(); - ValueNode oldReceiver = callTarget.arguments().get(0); - ValueNode newReceiver = oldReceiver; - if (newReceiver.getStackKind() == JavaKind.Object) { + try (DebugCloseable position = invoke.asNode().withNodeSourcePosition()) { + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + assert !callTarget.isStatic() : callTarget.targetMethod(); + StructuredGraph graph = callTarget.graph(); + ValueNode oldReceiver = callTarget.arguments().get(0); + ValueNode newReceiver = oldReceiver; + if (newReceiver.getStackKind() == JavaKind.Object) { - if (invoke.getInvokeKind() == InvokeKind.Special) { - Stamp paramStamp = newReceiver.stamp(NodeView.DEFAULT); - Stamp stamp = paramStamp.join(StampFactory.object(TypeReference.create(graph.getAssumptions(), callTarget.targetMethod().getDeclaringClass()))); - if (!stamp.equals(paramStamp)) { - // The verifier and previous optimizations guarantee unconditionally that the - // receiver is at least of the type of the method holder for a special invoke. - newReceiver = graph.unique(new PiNode(newReceiver, stamp)); + if (invoke.getInvokeKind() == InvokeKind.Special) { + Stamp paramStamp = newReceiver.stamp(NodeView.DEFAULT); + Stamp stamp = paramStamp.join(StampFactory.object(TypeReference.create(graph.getAssumptions(), callTarget.targetMethod().getDeclaringClass()))); + if (!stamp.equals(paramStamp)) { + // The verifier and previous optimizations guarantee unconditionally that + // the + // receiver is at least of the type of the method holder for a special + // invoke. + newReceiver = graph.unique(new PiNode(newReceiver, stamp)); + } + } + + if (!StampTool.isPointerNonNull(newReceiver)) { + LogicNode condition = graph.unique(IsNullNode.create(newReceiver)); + FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); + PiNode nonNullReceiver = graph.unique(new PiNode(newReceiver, StampFactory.objectNonNull(), fixedGuard)); + graph.addBeforeFixed(invoke.asNode(), fixedGuard); + newReceiver = nonNullReceiver; } } - if (!StampTool.isPointerNonNull(newReceiver)) { - LogicNode condition = graph.unique(IsNullNode.create(newReceiver)); - FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); - PiNode nonNullReceiver = graph.unique(new PiNode(newReceiver, StampFactory.objectNonNull(), fixedGuard)); - graph.addBeforeFixed(invoke.asNode(), fixedGuard); - newReceiver = nonNullReceiver; + if (newReceiver != oldReceiver) { + callTarget.replaceFirstInput(oldReceiver, newReceiver); } + return newReceiver; } - - if (newReceiver != oldReceiver) { - callTarget.replaceFirstInput(oldReceiver, newReceiver); - } - return newReceiver; } public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target, int invokeBci) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java index 5aa39e04f52..cbdf7648968 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.info; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.StructuredGraph; @@ -54,10 +54,10 @@ public abstract class AbstractInlineInfo implements InlineInfo { } @SuppressWarnings("try") - protected static EconomicSet inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, boolean receiverNullCheck) { + protected static EconomicSet inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, boolean receiverNullCheck, String reason) { assert inlineable instanceof InlineableGraph; StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph(); - return InliningUtil.inlineForCanonicalization(invoke, calleeGraph, receiverNullCheck, concrete); + return InliningUtil.inlineForCanonicalization(invoke, calleeGraph, receiverNullCheck, concrete, reason, "InliningPhase"); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java index 8d53ec09dba..9b7bf7d16ce 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.info; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.Invoke; @@ -46,9 +46,9 @@ public class AssumptionInlineInfo extends ExactInlineInfo { } @Override - public EconomicSet inline(Providers providers) { + public EconomicSet inline(Providers providers, String reason) { takenAssumption.recordTo(invoke.asNode().graph().getAssumptions()); - return super.inline(providers); + return super.inline(providers, reason); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java index d610ab6a2e7..1b8ea1a0572 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.info; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable; @@ -51,8 +51,8 @@ public class ExactInlineInfo extends AbstractInlineInfo { } @Override - public EconomicSet inline(Providers providers) { - return inline(invoke, concrete, inlineableElement, !suppressNullCheck); + public EconomicSet inline(Providers providers, String reason) { + return inline(invoke, concrete, inlineableElement, !suppressNullCheck, reason); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java index b778e43b7c4..bf5aa6bcdff 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.info; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.StructuredGraph; @@ -75,7 +75,7 @@ public interface InlineInfo { * * @return a collection of nodes that need to be canonicalized after the inlining */ - EconomicSet inline(Providers providers); + EconomicSet inline(Providers providers, String reason); /** * Try to make the call static bindable to avoid interface and virtual method calls. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java index 982c8a4bd13..ce08c119d11 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java @@ -25,8 +25,8 @@ package org.graalvm.compiler.phases.common.inlining.info; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -156,11 +156,11 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { } @Override - public EconomicSet inline(Providers providers) { + public EconomicSet inline(Providers providers, String reason) { if (hasSingleMethod()) { - return inlineSingleMethod(graph(), providers.getStampProvider(), providers.getConstantReflection()); + return inlineSingleMethod(graph(), providers.getStampProvider(), providers.getConstantReflection(), reason); } else { - return inlineMultipleMethods(graph(), providers); + return inlineMultipleMethods(graph(), providers, reason); } } @@ -182,7 +182,7 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { return notRecordedTypeProbability > 0; } - private EconomicSet inlineMultipleMethods(StructuredGraph graph, Providers providers) { + private EconomicSet inlineMultipleMethods(StructuredGraph graph, Providers providers, String reason) { int numberOfMethods = concretes.size(); FixedNode continuation = invoke.next(); @@ -277,7 +277,7 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { // do the actual inlining for every invoke for (int i = 0; i < numberOfMethods; i++) { Invoke invokeForInlining = (Invoke) successors[i].next(); - canonicalizeNodes.addAll(doInline(i, invokeForInlining)); + canonicalizeNodes.addAll(doInline(i, invokeForInlining, reason)); } if (returnValuePhi != null) { canonicalizeNodes.add(returnValuePhi); @@ -285,8 +285,8 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { return canonicalizeNodes; } - protected EconomicSet doInline(int index, Invoke invokeForInlining) { - return inline(invokeForInlining, methodAt(index), inlineableElementAt(index), false); + protected EconomicSet doInline(int index, Invoke invokeForInlining, String reason) { + return inline(invokeForInlining, methodAt(index), inlineableElementAt(index), false, reason); } private int getTypeCount(int concreteMethodIndex) { @@ -322,7 +322,7 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { return result; } - private EconomicSet inlineSingleMethod(StructuredGraph graph, StampProvider stampProvider, ConstantReflectionProvider constantReflection) { + private EconomicSet inlineSingleMethod(StructuredGraph graph, StampProvider stampProvider, ConstantReflectionProvider constantReflection, String reason) { assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; AbstractBeginNode calleeEntryNode = graph.add(new BeginNode()); @@ -333,7 +333,7 @@ public class MultiTypeGuardInlineInfo extends AbstractInlineInfo { calleeEntryNode.setNext(invoke.asNode()); - return inline(invoke, methodAt(0), inlineableElementAt(0), false); + return inline(invoke, methodAt(0), inlineableElementAt(0), false, reason); } private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, StampProvider stampProvider, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java index cbfe9aeee05..8bfda6139ef 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java @@ -22,8 +22,9 @@ */ package org.graalvm.compiler.phases.common.inlining.info; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.calc.CanonicalCondition; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.ConstantNode; @@ -98,9 +99,9 @@ public class TypeGuardInlineInfo extends AbstractInlineInfo { } @Override - public EconomicSet inline(Providers providers) { + public EconomicSet inline(Providers providers, String reason) { createGuard(graph(), providers); - return inline(invoke, concrete, inlineableElement, false); + return inline(invoke, concrete, inlineableElement, false, reason); } @Override @@ -109,19 +110,22 @@ public class TypeGuardInlineInfo extends AbstractInlineInfo { InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete); } + @SuppressWarnings("try") private void createGuard(StructuredGraph graph, Providers providers) { - ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke); - LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver)); - ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(NodeView.DEFAULT), providers.getConstantReflection().asObjectHub(type), providers.getMetaAccess(), graph); + try (DebugCloseable context = invoke.asNode().withNodeSourcePosition()) { + ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke); + LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver)); + ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(NodeView.DEFAULT), providers.getConstantReflection().asObjectHub(type), providers.getMetaAccess(), graph); - LogicNode typeCheck = CompareNode.createCompareNode(graph, CanonicalCondition.EQ, receiverHub, typeHub, providers.getConstantReflection(), NodeView.DEFAULT); - FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); - assert invoke.predecessor() != null; + LogicNode typeCheck = CompareNode.createCompareNode(graph, CanonicalCondition.EQ, receiverHub, typeHub, providers.getConstantReflection(), NodeView.DEFAULT); + FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); + assert invoke.predecessor() != null; - ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true); - invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver); + ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true); + invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver); - graph.addBeforeFixed(invoke.asNode(), guard); + graph.addBeforeFixed(invoke.asNode(), guard); + } } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java index d49985e394a..e50c0c8009e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java @@ -27,6 +27,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.LimitInlinedInvokes; import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize; import static org.graalvm.compiler.core.common.GraalOptions.MaximumInliningSize; import static org.graalvm.compiler.core.common.GraalOptions.SmallCompiledLowLevelGraphSize; +import static org.graalvm.compiler.core.common.GraalOptions.TraceInlining; import static org.graalvm.compiler.core.common.GraalOptions.TrivialInliningSize; import java.util.Map; @@ -61,8 +62,8 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { } @Override - public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { - + public Decision isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + final boolean isTracing = TraceInlining.getValue(replacements.getOptions()); final InlineInfo info = invocation.callee(); OptionValues options = info.graph().getOptions(); final double probability = invocation.probability(); @@ -70,17 +71,17 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { if (InlineEverything.getValue(options)) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "inline everything"); } if (isIntrinsic(replacements, info)) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "intrinsic"); } if (info.shouldInline()) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "forced inlining"); } double inliningBonus = getInliningBonus(info); @@ -90,12 +91,13 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { if (SmallCompiledLowLevelGraphSize.getValue(options) > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue(options) * inliningBonus) { InliningUtil.traceNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize, relevance, probability, inliningBonus, nodes); - return false; + return InliningPolicy.Decision.NO.withReason(isTracing, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize, + relevance, probability, inliningBonus, nodes); } if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); } /* @@ -108,17 +110,19 @@ public class GreedyInliningPolicy extends AbstractInliningPolicy { if (LimitInlinedInvokes.getValue(options) > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue(options) * inliningBonus) { InliningUtil.traceNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance, probability, inliningBonus, nodes); - return false; + return InliningPolicy.Decision.NO.withReason(isTracing, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance, + probability, inliningBonus, nodes); } double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue(options) * inliningBonus)); if (nodes <= maximumNodes) { InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, nodes, maximumNodes); - return true; + return InliningPolicy.Decision.YES.withReason(isTracing, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, + nodes, maximumNodes); } InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); - return false; + return InliningPolicy.Decision.NO.withReason(isTracing, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java index d680b7f8649..0a526358f5d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineEverythingPolicy.java @@ -24,6 +24,7 @@ package org.graalvm.compiler.phases.common.inlining.policy; import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.spi.Replacements; @@ -41,7 +42,7 @@ public class InlineEverythingPolicy implements InliningPolicy { } @Override - public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { - return true; + public Decision isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + return Decision.YES.withReason(GraalOptions.TraceInlining.getValue(replacements.getOptions()), "inline everything"); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java index 0af953c9acb..bf51d1d61a5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.policy; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.spi.Replacements; @@ -35,14 +36,15 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public final class InlineMethodSubstitutionsPolicy extends InlineEverythingPolicy { @Override - public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + public Decision isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + final boolean isTracing = GraalOptions.TraceInlining.getValue(replacements.getOptions()); CallTargetNode callTarget = invocation.callee().invoke().callTarget(); if (callTarget instanceof MethodCallTargetNode) { ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod(); if (replacements.hasSubstitution(calleeMethod, invocation.callee().invoke().bci())) { - return true; + return Decision.YES.withReason(isTracing, "has a method subtitution"); } } - return false; + return Decision.NO.withReason(isTracing, "does not have a method substitution"); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java index 5ac832f22ec..bb21d5da8c9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InliningPolicy.java @@ -27,8 +27,36 @@ import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.phases.common.inlining.walker.MethodInvocation; public interface InliningPolicy { + class Decision { + public static final Decision YES = new Decision(true, "(unknown reason)"); + public static final Decision NO = new Decision(false, "(unknown reason)"); + + private final boolean shouldInline; + private final String reason; + + private Decision(boolean shouldInline, String reason) { + this.shouldInline = shouldInline; + this.reason = reason; + } + + public boolean shouldInline() { + return shouldInline; + } + + public String getReason() { + return reason; + } + + public Decision withReason(boolean isTracing, String newReason, Object... args) { + if (isTracing) { + return new Decision(shouldInline, String.format(newReason, args)); + } else { + return this; + } + } + } boolean continueInlining(StructuredGraph graph); - boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed); + Decision isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java index 777eaadcd6e..3f2509aef1e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java @@ -26,8 +26,8 @@ import java.util.BitSet; import java.util.LinkedList; import java.util.function.ToDoubleFunction; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.ParameterNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java index 640febe9809..a380d9d075a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java @@ -25,8 +25,8 @@ package org.graalvm.compiler.phases.common.inlining.walker; import java.util.ArrayList; import java.util.function.ToDoubleFunction; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeWorkList; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java index 2411202e9ee..cdef4b06283 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java @@ -34,8 +34,8 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; @@ -167,6 +167,7 @@ public class InliningData { return true; } else { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), method, failureMessage); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, failureMessage); return false; } } @@ -258,12 +259,14 @@ public class InliningData { JavaTypeProfile typeProfile = ((MethodCallTargetNode) invoke.callTarget()).getProfile(); if (typeProfile == null) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no type profile exists"); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "no type profile exists"); return null; } JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes(); if (ptypes == null || ptypes.length <= 0) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types in profile"); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "no types in profile"); return null; } ResolvedJavaType contextType = invoke.getContextType(); @@ -273,6 +276,7 @@ public class InliningData { if (ptypes.length == 1 && notRecordedTypeProbability == 0) { if (!optimisticOpts.inlineMonomorphicCalls(options)) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled"); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "inlining monomorphic calls is disabled"); return null; } @@ -288,6 +292,7 @@ public class InliningData { if (!optimisticOpts.inlinePolymorphicCalls(options) && notRecordedTypeProbability == 0) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "inlining polymorphic calls is disabled (%d types)", ptypes.length); return null; } if (!optimisticOpts.inlineMegamorphicCalls(options) && notRecordedTypeProbability > 0) { @@ -295,6 +300,8 @@ public class InliningData { // the number of types is lower than what can be recorded in a type profile InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability * 100); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, + "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length, notRecordedTypeProbability); return null; } @@ -305,6 +312,7 @@ public class InliningData { ResolvedJavaMethod concrete = ptypes[i].getType().resolveConcreteMethod(targetMethod, contextType); if (concrete == null) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "could not resolve method"); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "could not resolve method"); return null; } int index = concreteMethods.indexOf(concrete); @@ -333,6 +341,8 @@ public class InliningData { // No method left that is worth inlining. InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size()); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, + "no methods remaining after filtering less frequent methods (%d methods previously)", concreteMethods.size()); return null; } @@ -342,6 +352,7 @@ public class InliningData { if (concreteMethods.size() > maxMethodPerInlining) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "polymorphic call with more than %d target methods", maxMethodPerInlining); return null; } @@ -363,12 +374,16 @@ public class InliningData { if (usedTypes.isEmpty()) { // No type left that is worth checking for. InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, "no types remaining after filtering less frequent types (%d types previously)", + ptypes.length); return null; } for (ResolvedJavaMethod concrete : concreteMethods) { if (!checkTargetConditions(invoke, concrete)) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); + invoke.asNode().graph().getInliningLog().addDecision(invoke, false, "InliningPhase", null, null, + "it is a polymorphic method call and at least one invoked method cannot be inlined"); return null; } } @@ -393,14 +408,14 @@ public class InliningData { } @SuppressWarnings("try") - private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation) { + private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation, String reason) { StructuredGraph callerGraph = callerCallsiteHolder.graph(); InlineInfo calleeInfo = calleeInvocation.callee(); try { try (DebugContext.Scope scope = debug.scope("doInline", callerGraph)) { EconomicSet canonicalizedNodes = EconomicSet.create(Equivalence.IDENTITY); canonicalizedNodes.addAll(calleeInfo.invoke().asNode().usages()); - EconomicSet parameterUsages = calleeInfo.inline(new Providers(context)); + EconomicSet parameterUsages = calleeInfo.inline(new Providers(context), reason); canonicalizedNodes.addAll(parameterUsages); counterInliningRuns.increment(debug); debug.dump(DebugContext.DETAILED_LEVEL, callerGraph, "after %s", calleeInfo); @@ -449,8 +464,9 @@ public class InliningData { assert callerCallsiteHolder.containsInvoke(calleeInfo.invoke()); counterInliningConsidered.increment(debug); - if (inliningPolicy.isWorthInlining(context.getReplacements(), calleeInvocation, inliningDepth, true)) { - doInline(callerCallsiteHolder, calleeInvocation); + InliningPolicy.Decision decision = inliningPolicy.isWorthInlining(context.getReplacements(), calleeInvocation, inliningDepth, true); + if (decision.shouldInline()) { + doInline(callerCallsiteHolder, calleeInvocation, decision.getReason()); return true; } @@ -483,7 +499,7 @@ public class InliningData { *

* The {@link InlineInfo} used to get things rolling is kept around in the * {@link MethodInvocation}, it will be needed in case of inlining, see - * {@link InlineInfo#inline(Providers)} + * {@link InlineInfo#inline(Providers, String)} *

*/ private void processNextInvoke() { @@ -709,7 +725,7 @@ public class InliningData { final MethodInvocation currentInvocation = currentInvocation(); - final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(context.getReplacements(), currentInvocation, inliningDepth(), false)); + final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(context.getReplacements(), currentInvocation, inliningDepth(), false).shouldInline()); if (backtrack) { int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs(); assert remainingGraphs > 0; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java index ad7292148b1..121840f7519 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java @@ -26,8 +26,8 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.Set; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.graph.Graph.NodeEvent; import org.graalvm.compiler.graph.Graph.NodeEventListener; import org.graalvm.compiler.graph.Node; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java index e4339631881..c9080db91b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java @@ -26,8 +26,8 @@ import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilit import java.util.function.ToDoubleFunction; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java index 0e6198540c1..7c7e4a075c0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java @@ -27,8 +27,8 @@ import java.util.ArrayList; import java.util.Deque; import java.util.Set; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeBitMap; import org.graalvm.compiler.nodes.AbstractBeginNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java index c2c128fc5fa..5500b9b3928 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java @@ -28,8 +28,8 @@ import java.util.Deque; import java.util.List; import java.util.function.Predicate; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.RetryableBailoutException; import org.graalvm.compiler.core.common.cfg.Loop; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java index 14e7b1d46e6..852c243a2e2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java @@ -28,9 +28,9 @@ import java.util.Deque; import java.util.Iterator; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java index f956235d462..a52f814f80d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java @@ -27,8 +27,8 @@ import java.util.ArrayList; import java.util.Deque; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeBitMap; import org.graalvm.compiler.nodes.AbstractBeginNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java index 8e96078a0c0..accf90af1ab 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java @@ -24,8 +24,8 @@ package org.graalvm.compiler.phases.schedule; import java.util.List; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugContext; @@ -42,7 +42,7 @@ import org.graalvm.compiler.nodes.memory.MemoryNode; import org.graalvm.compiler.nodes.memory.MemoryPhiNode; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public final class MemoryScheduleVerification extends BlockIteratorClosure> { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java index 7e2e51f3237..9f0e3ddfb2a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.phases.schedule; -import static org.graalvm.collections.Equivalence.IDENTITY; +import static jdk.internal.vm.compiler.collections.Equivalence.IDENTITY; import static org.graalvm.compiler.core.common.GraalOptions.GuardPriorities; import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops; import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates; @@ -38,7 +38,7 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.function.Function; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.cfg.BlockMap; @@ -83,7 +83,7 @@ import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; import org.graalvm.compiler.nodes.spi.ValueProxy; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.Phase; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public final class SchedulePhase extends Phase { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java index 2a96d27dd08..2a1c036bb8b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/Suites.java @@ -22,6 +22,10 @@ */ package org.graalvm.compiler.phases.tiers; +import org.graalvm.compiler.lir.alloc.RegisterAllocationPhase; +import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.phases.LIRPhaseSuite; import org.graalvm.compiler.lir.phases.LIRSuites; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.PhaseSuite; @@ -56,7 +60,25 @@ public final class Suites { } public static LIRSuites createLIRSuites(CompilerConfiguration config, OptionValues options) { - return new LIRSuites(config.createPreAllocationOptimizationStage(options), config.createAllocationStage(options), config.createPostAllocationOptimizationStage(options)); + LIRPhaseSuite allocationStage = config.createAllocationStage(options); + assert verifyAllocationStage(allocationStage); + return new LIRSuites(config.createPreAllocationOptimizationStage(options), allocationStage, config.createPostAllocationOptimizationStage(options)); + } + + private static boolean verifyAllocationStage(LIRPhaseSuite allocationStage) { + boolean allocationPhase = false; + for (LIRPhase phase : allocationStage.getPhases()) { + if (phase instanceof RegisterAllocationPhase) { + if (allocationPhase) { + assert false : "More than one register allocation phase"; + return false; + } + allocationPhase = true; + } + + } + assert allocationPhase : "No register allocation phase"; + return allocationPhase; } public boolean isImmutable() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java index 7d00f6b0d3b..b8e067f5476 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java @@ -25,8 +25,8 @@ package org.graalvm.compiler.phases.util; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.GraalGraphError; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java index 35f39ffbd10..25139cc32e1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.phases.verify; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import java.lang.annotation.Annotation; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java index aba7840db1d..4eac74c3020 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.phases.verify; import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java index f51bb7f74c3..82aca2abdef 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java @@ -26,6 +26,9 @@ import static org.graalvm.compiler.graph.Edges.Type.Inputs; import static org.graalvm.compiler.graph.Edges.Type.Successors; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -72,17 +75,26 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.Signature; +import org.graalvm.graphio.GraphLocations; public class BinaryGraphPrinter implements GraphStructure, Edges>, GraphBlocks, GraphElements, + GraphLocations, GraphTypes, GraphPrinter { private final SnippetReflectionProvider snippetReflection; private final GraphOutput output; public BinaryGraphPrinter(DebugContext ctx, SnippetReflectionProvider snippetReflection) throws IOException { - this.output = ctx.buildOutput(GraphOutput.newBuilder(this).protocolVersion(5, 0).blocks(this).elements(this).types(this)); + // @formatter:off + this.output = ctx.buildOutput(GraphOutput.newBuilder(this). + protocolVersion(6, 0). + blocks(this). + elementsAndLocations(this, this). + types(this) + ); + // @formatter:on this.snippetReflection = snippetReflection; } @@ -266,17 +278,6 @@ public class BinaryGraphPrinter implements } props.put("category", "floating"); } - if (node.getNodeSourcePosition() != null) { - NodeSourcePosition pos = node.getNodeSourcePosition(); - while (pos != null) { - SourceLanguagePosition cur = pos.getSourceLanauage(); - if (cur != null) { - cur.addSourceInformation(props); - break; - } - pos = pos.getCaller(); - } - } if (getSnippetReflectionProvider() != null) { for (Map.Entry prop : props.entrySet()) { if (prop.getValue() instanceof JavaConstantFormattable) { @@ -502,6 +503,85 @@ public class BinaryGraphPrinter implements return method.asStackTraceElement(bci); } + @Override + public Iterable methodLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { + StackTraceElement e = methodStackTraceElement(method, bci, pos); + class JavaSourcePosition implements SourceLanguagePosition { + + @Override + public String toShortString() { + return e.toString(); + } + + @Override + public int getOffsetEnd() { + return -1; + } + + @Override + public int getOffsetStart() { + return -1; + } + + @Override + public int getLineNumber() { + return e.getLineNumber(); + } + + @Override + public URI getURI() { + String path = e.getFileName(); + try { + return path == null ? null : new URI(null, null, path, null); + } catch (URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + } + + @Override + public String getLanguage() { + return "Java"; + } + } + + List arr = new ArrayList<>(); + arr.add(new JavaSourcePosition()); + NodeSourcePosition at = pos; + while (at != null) { + SourceLanguagePosition cur = at.getSourceLanguage(); + if (cur != null) { + arr.add(cur); + } + at = at.getCaller(); + } + return arr; + } + + @Override + public String locationLanguage(SourceLanguagePosition location) { + return location.getLanguage(); + } + + @Override + public URI locationURI(SourceLanguagePosition location) { + return location.getURI(); + } + + @Override + public int locationLineNumber(SourceLanguagePosition location) { + return location.getLineNumber(); + } + + @Override + public int locationOffsetStart(SourceLanguagePosition location) { + return location.getOffsetStart(); + } + + @Override + public int locationOffsetEnd(SourceLanguagePosition location) { + return location.getOffsetEnd(); + } + static final class GraphInfo { final DebugContext debug; final Graph graph; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java index 9429831465d..b14d4a94764 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java @@ -33,7 +33,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeDisassembler; import org.graalvm.compiler.core.common.alloc.Trace; @@ -116,38 +116,38 @@ class CFGPrinter extends CompilationPrinter { } private void printBlock(BciBlockMapping.BciBlock block) { - out.print("name \"B").print(block.startBci).println('"'); - out.print("from_bci ").println(block.startBci); - out.print("to_bci ").println(block.endBci); + out.print("name \"B").print(block.getStartBci()).println('"'); + out.print("from_bci ").println(block.getStartBci()); + out.print("to_bci ").println(block.getEndBci()); out.println("predecessors "); out.print("successors "); for (BciBlockMapping.BciBlock succ : block.getSuccessors()) { - if (!succ.isExceptionEntry) { - out.print("\"B").print(succ.startBci).print("\" "); + if (!succ.isExceptionEntry()) { + out.print("\"B").print(succ.getStartBci()).print("\" "); } } out.println(); out.print("xhandlers"); for (BciBlockMapping.BciBlock succ : block.getSuccessors()) { - if (succ.isExceptionEntry) { - out.print("\"B").print(succ.startBci).print("\" "); + if (succ.isExceptionEntry()) { + out.print("\"B").print(succ.getStartBci()).print("\" "); } } out.println(); out.print("flags "); - if (block.isExceptionEntry) { + if (block.isExceptionEntry()) { out.print("\"ex\" "); } - if (block.isLoopHeader) { + if (block.isLoopHeader()) { out.print("\"plh\" "); } out.println(); - out.print("loop_depth ").println(Long.bitCount(block.loops)); + out.print("loop_depth ").println(Long.bitCount(block.getLoops())); } private NodeMap latestScheduling; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java index 5540cb4784c..0b8f2cdec25 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java @@ -37,15 +37,13 @@ import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.util.JavaConstantFormatter; import org.graalvm.compiler.phases.schedule.SchedulePhase; -import org.graalvm.compiler.serviceprovider.JDK9Method; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.runtime.JVMCI; -import jdk.vm.ci.services.Services; interface GraphPrinter extends Closeable, JavaConstantFormatter { @@ -71,16 +69,6 @@ interface GraphPrinter extends Closeable, JavaConstantFormatter { @Override void close(); - /** - * A JVMCI package dynamically exported to trusted modules. - */ - String JVMCI_RUNTIME_PACKAGE = JVMCI.class.getPackage().getName(); - - /** - * {@code jdk.vm.ci} module. - */ - Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule(Services.class); - /** * Classes whose {@link #toString()} method does not run any untrusted code. */ @@ -105,17 +93,8 @@ interface GraphPrinter extends Closeable, JavaConstantFormatter { if (TRUSTED_CLASSES.contains(c)) { return true; } - if (JDK9Method.JAVA_SPECIFICATION_VERSION < 9) { - if (c.getClassLoader() == Services.class.getClassLoader()) { - // Loaded by the JVMCI class loader - return true; - } - } else { - Object module = JDK9Method.getModule(c); - if (JVMCI_MODULE == module || JDK9Method.isOpenTo(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) { - // Can access non-statically-exported package in JVMCI - return true; - } + if (GraalServices.isToStringTrusted(c)) { + return true; } if (c.getClassLoader() == GraphPrinter.class.getClassLoader()) { return true; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java index 9b6f38b9f28..7fc77afc572 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java @@ -45,6 +45,7 @@ import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.contract.NodeCostUtil; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -86,11 +87,11 @@ public class GraphPrinterDumpHandler implements DebugDumpHandler { } private static String jvmArguments() { - try { - return String.join(" ", java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments()); - } catch (LinkageError err) { - return "unknown"; + List inputArguments = GraalServices.getInputArguments(); + if (inputArguments != null) { + return String.join(" ", inputArguments); } + return "unknown"; } private void ensureInitialized(DebugContext ctx, Graph graph) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java index b374d4317c1..a187f4b6d01 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java @@ -28,6 +28,7 @@ import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.Una import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static org.graalvm.compiler.serviceprovider.GraalServices.JAVA_SPECIFICATION_VERSION; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.nodes.ValueNode; @@ -53,6 +54,9 @@ public class AArch64GraphBuilderPlugins { registerIntegerLongPlugins(invocationPlugins, AArch64IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider); registerIntegerLongPlugins(invocationPlugins, AArch64LongSubstitutions.class, JavaKind.Long, bytecodeProvider); registerMathPlugins(invocationPlugins); + registerStringLatin1Plugins(invocationPlugins, bytecodeProvider); + registerStringUTF16Plugins(invocationPlugins, bytecodeProvider); + } }); } @@ -114,4 +118,23 @@ public class AArch64GraphBuilderPlugins { } }); } + + private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { + if (JAVA_SPECIFICATION_VERSION >= 9) { + Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider); + r.setAllowOverwrite(true); + r.registerMethodSubstitution(AArch64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class); + r.registerMethodSubstitution(AArch64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class); + } + } + + private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { + if (JAVA_SPECIFICATION_VERSION >= 9) { + Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider); + r.setAllowOverwrite(true); + r.registerMethodSubstitution(AArch64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class); + r.registerMethodSubstitution(AArch64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class); + } + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringLatin1Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringLatin1Substitutions.java new file mode 100644 index 00000000000..b369f757471 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringLatin1Substitutions.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 org.graalvm.compiler.replacements.aarch64; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; + +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@code java.lang.StringLatin1} methods. + * + * Since JDK 9. + */ +@ClassSubstitution(className = "java.lang.StringLatin1", optional = true) +public class AArch64StringLatin1Substitutions { + + /** + * @param value is byte[] + * @param other is char[] + */ + @MethodSubstitution + public static int compareTo(byte[] value, byte[] other) { + return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Byte); + } + + /** + * @param value is byte[] + * @param other is char[] + */ + @MethodSubstitution + public static int compareToUTF16(byte[] value, byte[] other) { + return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Char); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringUTF16Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringUTF16Substitutions.java new file mode 100644 index 00000000000..ef45d8c80eb --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64StringUTF16Substitutions.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 org.graalvm.compiler.replacements.aarch64; + +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; + +import jdk.vm.ci.meta.JavaKind; + +// JaCoCo Exclude + +/** + * Substitutions for {@code java.lang.StringUTF16} methods. + * + * Since JDK 9. + */ +@ClassSubstitution(className = "java.lang.StringUTF16", optional = true) +public class AArch64StringUTF16Substitutions { + + /** + * @param value is char[] + * @param other is char[] + */ + @MethodSubstitution + public static int compareTo(byte[] value, byte[] other) { + return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Char, JavaKind.Char); + } + + /** + * @param value is char[] + * @param other is byte[] + */ + @MethodSubstitution + public static int compareToLatin1(byte[] value, byte[] other) { + /* + * Swapping array arguments because intrinsic expects order to be byte[]/char[] but kind + * arguments stay in original order. + */ + return ArrayCompareToNode.compareTo(other, value, other.length, value.length, JavaKind.Char, JavaKind.Byte); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index c2cb77fbee9..7467d4261d1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -29,8 +29,8 @@ import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.Una import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; -import static org.graalvm.compiler.serviceprovider.JDK9Method.JAVA_SPECIFICATION_VERSION; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.JAVA_SPECIFICATION_VERSION; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import java.util.Arrays; @@ -57,7 +57,7 @@ import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOpe import org.graalvm.compiler.replacements.nodes.BitCountNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; @@ -194,8 +194,7 @@ public class AMD64GraphBuilderPlugins { r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class, int.class, char[].class, int.class, int.class, int.class); } - // r.registerMethodSubstitution(AMD64StringSubstitutions.class, "compareTo", - // Receiver.class, String.class); + r.registerMethodSubstitution(AMD64StringSubstitutions.class, "compareTo", Receiver.class, String.class); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java index 67e858a0cdb..73697f99966 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java @@ -38,8 +38,8 @@ import org.graalvm.compiler.nodes.memory.MemoryAccess; import org.graalvm.compiler.nodes.memory.MemoryNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java index 9265db87a57..12b2dd83c8c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.replacements.StringSubstitutions; import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; import org.graalvm.compiler.word.Word; -import org.graalvm.word.Pointer; +import jdk.internal.vm.compiler.word.Pointer; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java index e1758a69ece..198aaf99859 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java @@ -22,12 +22,20 @@ */ package org.graalvm.compiler.replacements.test; +import static org.graalvm.compiler.core.common.GraalOptions.RemoveNeverExecutedCode; +import static org.graalvm.compiler.core.common.GraalOptions.UseExceptionProbability; +import static org.graalvm.compiler.core.common.GraalOptions.UseTypeCheckHints; + import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.phases.HighTier; import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.options.OptionValues; +import org.junit.Ignore; import org.junit.Test; +import jdk.vm.ci.meta.ResolvedJavaMethod; + public class NestedExceptionHandlerTest extends GraalCompilerTest { @BytecodeParserNeverInline(invokeWithException = true) @@ -63,4 +71,67 @@ public class NestedExceptionHandlerTest extends GraalCompilerTest { test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "nestedExceptionHandler"); } + @SuppressWarnings("try") + public static String snippet1() { + try { + synchronized (String.class) { + try (AutoCloseable scope = null) { + return "RETURN"; + } catch (Throwable t) { + return t.toString(); + } + } + } finally { + raise(); + } + } + + public static void raise() { + throw new RuntimeException(); + } + + @SuppressWarnings("try") + public static String snippet2() { + try { + synchronized (String.class) { + try (AutoCloseable scope = null) { + return performCompilation(); + } catch (Throwable t) { + return t.toString(); + } + } + } finally { + synchronized (String.class) { + String.class.toString(); + } + } + } + + private static String performCompilation() { + return "passed"; + } + + @Ignore("https://bugs.eclipse.org/bugs/show_bug.cgi?id=533187") + @Test + public void testSnippet1() { + OptionValues options = parseAllCodeWithoutInlining(); + ResolvedJavaMethod method = getResolvedJavaMethod("snippet1"); + parseEager(method, AllowAssumptions.YES, options); + } + + @Ignore("https://bugs.eclipse.org/bugs/show_bug.cgi?id=533187") + @Test + public void testSnippet2() { + OptionValues options = parseAllCodeWithoutInlining(); + ResolvedJavaMethod method = getResolvedJavaMethod("snippet2"); + parseEager(method, AllowAssumptions.YES, options); + } + + private static OptionValues parseAllCodeWithoutInlining() { + OptionValues options = new OptionValues(getInitialOptions(), + UseTypeCheckHints, false, + UseExceptionProbability, false, + RemoveNeverExecutedCode, false); + return options; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java index 7eb29a16c78..4a4b116c35e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java @@ -33,9 +33,9 @@ import org.graalvm.compiler.nodes.extended.JavaReadNode; import org.graalvm.compiler.nodes.extended.JavaWriteNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.word.ObjectAccess; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordFactory; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java index 519a7e23fcd..057f63b4349 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java @@ -45,7 +45,7 @@ import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; import org.graalvm.compiler.replacements.CachingPEGraphDecoder; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import org.junit.Test; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java index 48d6f19f8c3..e3b20f5c84e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java @@ -37,9 +37,9 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordCastNode; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.WordFactory; import org.junit.Assert; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java index 04692372114..a6ea4e177e5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java @@ -62,7 +62,7 @@ import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; import org.graalvm.compiler.phases.common.GuardLoweringPhase; import org.graalvm.compiler.phases.common.LoweringPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java index 53f0901c718..ba35f1c0693 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java @@ -26,10 +26,10 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; import org.junit.Assert; import org.junit.Assume; -import org.junit.Ignore; import org.junit.Test; import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -49,6 +49,7 @@ public class StringCompareToTest extends MethodSubstitutionTest { "\uFF21\uFF21", "\u043c\u0430\u043c\u0430\u0020\u043c\u044b\u043b\u0430\u0020\u0440\u0430\u043c\u0443\u002c\u0020\u0440\u0430\u043c\u0430\u0020\u0441\u044a\u0435\u043b\u0430\u0020\u043c\u0430\u043c\u0443", "crazy dog jumps over laszy fox", + "some-string\0xff", "XMM-XMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-", "XMM-XMM+YMM-YMM-ZMM-ZMM-ZMM-ZMM-", "XMM-XMM-YMM-YMM+ZMM-ZMM-ZMM-ZMM-", @@ -61,7 +62,7 @@ public class StringCompareToTest extends MethodSubstitutionTest { }; public StringCompareToTest() { - Assume.assumeTrue(getTarget().arch instanceof AMD64); + Assume.assumeTrue((getTarget().arch instanceof AMD64) || (getTarget().arch instanceof AArch64)); realMethod = getResolvedJavaMethod(String.class, "compareTo", String.class); testMethod = getResolvedJavaMethod("stringCompareTo"); @@ -91,24 +92,35 @@ public class StringCompareToTest extends MethodSubstitutionTest { } @Test - @Ignore("GR-8748") public void testEqualString() { String s = "equal-string"; executeStringCompareTo(s, new String(s.toCharArray())); } @Test - @Ignore("GR-8748") public void testDifferentString() { - executeStringCompareTo("some-string", "different-string"); + // Smoke test for primary cases + executeStringCompareTo("AAAAAAAA", ""); + // LL + executeStringCompareTo("some-stringA", "some-string\0xff"); + // UU + executeStringCompareTo("\u2241AAAAAAAB", "\u2241\u0041\u0041\u0041\u0041\u0041\u0041\u0041\uFF41"); + // LU + executeStringCompareTo("AAAAAAAAB", "\u0041\u0041\u0041\u0041\u0041\u0041\u0041\u0041\uFF41"); } @Test - @Ignore("GR-8748") public void testAllStrings() { for (String s0 : testData) { for (String s1 : testData) { - executeStringCompareTo(s0, s1); + try { + executeStringCompareTo(s0, s1); + } catch (AssertionError ex) { + System.out.println("FAIL: '" + ex + "'"); + System.out.println(" ***: s0 '" + s0 + "'"); + System.out.println(" ***: s1 '" + s1 + "'"); + throw ex; + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java index 6d463ca3e47..6ad9a83527e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java @@ -29,10 +29,10 @@ import org.graalvm.compiler.nodes.StructuredGraph.Builder; import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.word.Word; -import org.graalvm.word.Pointer; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordBase; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.UnsignedWord; +import jdk.internal.vm.compiler.word.WordBase; +import jdk.internal.vm.compiler.word.WordFactory; import org.junit.Test; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java index ed4f9a42c94..6be3d729e67 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java @@ -149,7 +149,7 @@ public class ClassfileBytecodeProviderTest extends GraalCompilerTest { for (final Enumeration entry = zipFile.entries(); entry.hasMoreElements();) { final ZipEntry zipEntry = entry.nextElement(); String name = zipEntry.getName(); - if (name.endsWith(".class") && !name.equals("module-info.class")) { + if (name.endsWith(".class") && !name.equals("module-info.class") && !name.startsWith("META-INF/versions/")) { String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); if (isInNativeImage(className)) { /* diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java index 1071d271c56..90e116c6662 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.replacements; import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; -import org.graalvm.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.SourceLanguagePositionProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java index 60193bff6ac..1e1d457237b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java @@ -48,6 +48,7 @@ import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; +import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -131,7 +132,7 @@ import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.MemoryBarriers; @@ -526,7 +527,8 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue()); AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset())); - LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, compareAndSwapBarrierType(cas))); + BarrierType barrierType = storeBarrierType(cas.object(), expectedValue); + LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, barrierType)); atomicNode.setStateAfter(cas.stateAfter()); graph.replaceFixedWithFixed(cas, atomicNode); } @@ -538,7 +540,8 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue()); AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset())); - LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, atomicReadAndWriteBarrierType(n))); + BarrierType barrierType = storeBarrierType(n.object(), n.newValue()); + LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, barrierType)); memoryRead.setStateAfter(n.stateAfter()); ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead); @@ -673,6 +676,7 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { memoryWrite.setGuard(write.getGuard()); } + @SuppressWarnings("try") protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) { StructuredGraph graph = commit.graph(); if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { @@ -685,10 +689,12 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); int entryCount = virtual.entryCount(); AbstractNewObjectNode newObject; - if (virtual instanceof VirtualInstanceNode) { - newObject = graph.add(createNewInstanceFromVirtual(virtual)); - } else { - newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph))); + try (DebugCloseable nsp = virtual.withNodeSourcePosition()) { + if (virtual instanceof VirtualInstanceNode) { + newObject = graph.add(createNewInstanceFromVirtual(virtual)); + } else { + newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph))); + } } recursiveLowerings.add(newObject); graph.addBeforeFixed(commit, newObject); @@ -884,23 +890,15 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { return entryKind == JavaKind.Object ? BarrierType.PRECISE : BarrierType.NONE; } - protected BarrierType unsafeStoreBarrierType(RawStoreNode store) { + private static BarrierType unsafeStoreBarrierType(RawStoreNode store) { if (!store.needsBarrier()) { return BarrierType.NONE; } return storeBarrierType(store.object(), store.value()); } - protected BarrierType compareAndSwapBarrierType(UnsafeCompareAndSwapNode cas) { - return storeBarrierType(cas.object(), cas.expected()); - } - - protected BarrierType atomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) { - return storeBarrierType(n.object(), n.newValue()); - } - - protected BarrierType storeBarrierType(ValueNode object, ValueNode value) { - if (value.getStackKind() == JavaKind.Object) { + private static BarrierType storeBarrierType(ValueNode object, ValueNode value) { + if (value.getStackKind() == JavaKind.Object && object.getStackKind() == JavaKind.Object) { ResolvedJavaType type = StampTool.typeOrNull(object); if (type != null && !type.isArray()) { return BarrierType.IMPRECISE; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java index 7617143bb1e..9119d09d536 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java @@ -29,10 +29,12 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; +import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node.ValueNumberable; @@ -71,7 +73,7 @@ import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality; import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -99,9 +101,20 @@ public class GraphKit implements GraphBuilderTool { protected abstract static class Structure { } - public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) { + public GraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name) { this.providers = providers; - this.graph = graph; + StructuredGraph.Builder builder = new StructuredGraph.Builder(debug.getOptions(), debug).compilationId(compilationId); + if (name != null) { + builder.name(name); + } else { + builder.method(stubMethod); + } + this.graph = builder.build(); + graph.disableUnsafeAccessTracking(); + if (graph.trackNodeSourcePosition()) { + // Set up a default value that everything constructed by GraphKit will use. + graph.withNodeSourcePosition(NodeSourcePosition.substitution(stubMethod)); + } this.wordTypes = wordTypes; this.graphBuilderPlugins = graphBuilderPlugins; this.lastFixedNode = graph.start(); @@ -229,7 +242,7 @@ public class GraphKit implements GraphBuilderTool { */ @SuppressWarnings("try") public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { - try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.placeholder(method))) { + try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(graph.currentNodeSourcePosition(), method))) { assert method.isStatic() == (invokeKind == InvokeKind.Static); Signature signature = method.getSignature(); JavaType returnType = signature.getReturnType(null); @@ -254,15 +267,29 @@ public class GraphKit implements GraphBuilderTool { } } + @SuppressWarnings("try") public InvokeWithExceptionNode createInvokeWithExceptionAndUnwind(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci, ValueNode... args) { + try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(graph.currentNodeSourcePosition(), method))) { + InvokeWithExceptionNode result = startInvokeWithException(method, invokeKind, frameStateBuilder, invokeBci, exceptionEdgeBci, args); + exceptionPart(); + ExceptionObjectNode exception = exceptionObject(); + append(new UnwindNode(exception)); + endInvokeWithException(); + return result; + } + } - InvokeWithExceptionNode result = startInvokeWithException(method, invokeKind, frameStateBuilder, invokeBci, exceptionEdgeBci, args); - exceptionPart(); - ExceptionObjectNode exception = exceptionObject(); - append(new UnwindNode(exception)); - endInvokeWithException(); - return result; + @SuppressWarnings("try") + public InvokeWithExceptionNode createInvokeWithExceptionAndUnwind(MethodCallTargetNode callTarget, FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci) { + try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(graph.currentNodeSourcePosition(), callTarget.targetMethod()))) { + InvokeWithExceptionNode result = startInvokeWithException(callTarget, frameStateBuilder, invokeBci, exceptionEdgeBci); + exceptionPart(); + ExceptionObjectNode exception = exceptionObject(); + append(new UnwindNode(exception)); + endInvokeWithException(); + return result; + } } protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, @SuppressWarnings("unused") int bci) { @@ -305,10 +332,10 @@ public class GraphKit implements GraphBuilderTool { /** * Recursively {@linkplain #inline inlines} all invocations currently in the graph. */ - public void inlineInvokes() { + public void inlineInvokes(String reason, String phase) { while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) { for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) { - inline(invoke); + inline(invoke, reason, phase); } } @@ -320,7 +347,7 @@ public class GraphKit implements GraphBuilderTool { * Inlines a given invocation to a method. The graph of the inlined method is processed in the * same manner as for snippets and method substitutions. */ - public void inline(InvokeNode invoke) { + public void inline(InvokeNode invoke, String reason, String phase) { ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); MetaAccessProvider metaAccess = providers.getMetaAccess(); @@ -341,7 +368,7 @@ public class GraphKit implements GraphBuilderTool { calleeGraph.clearAllStateAfter(); new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph); - InliningUtil.inline(invoke, calleeGraph, false, method); + InliningUtil.inline(invoke, calleeGraph, false, method, reason, phase); } protected void pushStructure(Structure structure) { @@ -493,6 +520,11 @@ public class GraphKit implements GraphBuilderTool { if (returnStamp == null) { returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); } + MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, invokeBci)); + return startInvokeWithException(callTarget, frameStateBuilder, invokeBci, exceptionEdgeBci); + } + + public InvokeWithExceptionNode startInvokeWithException(MethodCallTargetNode callTarget, FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci) { ExceptionObjectNode exceptionObject = add(new ExceptionObjectNode(getMetaAccess())); if (frameStateBuilder != null) { FrameStateBuilder exceptionState = frameStateBuilder.copy(); @@ -501,7 +533,6 @@ public class GraphKit implements GraphBuilderTool { exceptionState.setRethrowException(false); exceptionObject.setStateAfter(exceptionState.create(exceptionEdgeBci, exceptionObject)); } - MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, invokeBci)); InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionObject, invokeBci)); AbstractBeginNode noExceptionEdge = graph.add(KillingBeginNode.create(LocationIdentity.any())); invoke.setNext(noExceptionEdge); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java index 48ebe3e562e..4188ec64900 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/MethodHandlePlugin.java @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.replacements; +import static org.graalvm.compiler.core.common.GraalOptions.MaximumRecursiveInlining; + import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.graph.NodeInputList; import org.graalvm.compiler.nodes.CallTargetNode; @@ -46,6 +48,16 @@ public class MethodHandlePlugin implements NodePlugin { this.safeForDeoptimization = safeForDeoptimization; } + private static int countRecursiveInlining(GraphBuilderContext b, ResolvedJavaMethod method) { + int count = 0; + for (GraphBuilderContext c = b.getParent(); c != null; c = c.getParent()) { + if (method.equals(c.getMethod())) { + count++; + } + } + return count; + } + @Override public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method); @@ -83,11 +95,19 @@ public class MethodHandlePlugin implements NodePlugin { // As such, it needs to recursively inline everything. inlineEverything = args.length != argumentsList.size(); } - if (inlineEverything && !callTarget.targetMethod().hasBytecodes()) { + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + if (inlineEverything && !targetMethod.hasBytecodes()) { // we need to force-inline but we can not, leave the invoke as-is return false; } - b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), argumentsList.toArray(new ValueNode[argumentsList.size()]), inlineEverything); + + int recursionDepth = countRecursiveInlining(b, targetMethod); + int maxRecursionDepth = MaximumRecursiveInlining.getValue(b.getOptions()); + if (recursionDepth > maxRecursionDepth) { + return false; + } + + b.handleReplacedInvoke(invoke.getInvokeKind(), targetMethod, argumentsList.toArray(new ValueNode[argumentsList.size()]), inlineEverything); } return true; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java index 2c284bf1b1f..6a7ef953384 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java @@ -32,8 +32,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.core.common.PermanentBailoutException; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java index 45c3b8daed6..954c5a0f58c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java @@ -36,8 +36,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.Snippet; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java index b5fffd62580..a41892b5cce 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java @@ -50,7 +50,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; import org.graalvm.compiler.word.ObjectAccess; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.TargetDescription; import sun.misc.Unsafe; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java index a4499f5b1d0..97f7c5eb829 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java @@ -37,7 +37,7 @@ import org.graalvm.compiler.nodes.memory.MemoryAccess; import org.graalvm.compiler.nodes.memory.MemoryNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) public class SnippetLowerableMemoryNode extends FixedWithNextNode implements Lowerable, MemoryAccess { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java index fa80b3e1b1d..e5b102f4dfe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java @@ -30,7 +30,7 @@ import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.lang.reflect.Array; import java.lang.reflect.Method; @@ -47,10 +47,10 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.UnmodifiableEconomicMap; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter; @@ -131,8 +131,8 @@ import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode; import org.graalvm.util.CollectionsUtil; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordBase; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.WordBase; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.Constant; @@ -651,8 +651,9 @@ public class SnippetTemplate { try (DebugContext debug = openDebugContext(outer, args)) { try (DebugCloseable a = SnippetTemplateCreationTime.start(debug); DebugContext.Scope s = debug.scope("SnippetSpecialization", args.info.method)) { SnippetTemplates.increment(debug); - template = new SnippetTemplate(options, debug, providers, snippetReflection, args, graph.trackNodeSourcePosition(), replacee); - if (Options.UseSnippetTemplateCache.getValue(options) && args.cacheable) { + OptionValues snippetOptions = new OptionValues(options, GraalOptions.TraceInlining, GraalOptions.TraceInliningForStubsAndSnippets.getValue(options)); + template = new SnippetTemplate(snippetOptions, debug, providers, snippetReflection, args, graph.trackNodeSourcePosition(), replacee); + if (Options.UseSnippetTemplateCache.getValue(snippetOptions) && args.cacheable) { templates.put(args.cacheKey, template); } } catch (Throwable e) { @@ -1516,9 +1517,7 @@ public class SnippetTemplate { replaceeGraph.getInliningLog().addLog(duplicates, snippet.getInliningLog()); } NodeSourcePosition position = replacee.getNodeSourcePosition(); - if (position != null) { - InliningUtil.updateSourcePosition(replaceeGraph, duplicates, mark, position, true); - } + InliningUtil.updateSourcePosition(replaceeGraph, duplicates, mark, position, true); debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); return duplicates; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index 8793b1eba4d..d511f10bd13 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -105,7 +105,7 @@ import org.graalvm.compiler.replacements.nodes.VirtualizableInvokeMacroNode; import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactNode; import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactNode; import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; @@ -233,10 +233,10 @@ public class StandardGraphBuilderPlugins { // Ordered object-based accesses if (Java8OrEarlier) { if (kind == JavaKind.Int || kind == JavaKind.Long || kind == JavaKind.Object) { - r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true)); + r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, UnsafePutPlugin.putOrdered(kind)); } } else { - r.register4("put" + kindName + "Release", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true)); + r.register4("put" + kindName + "Release", Receiver.class, Object.class, long.class, javaClass, UnsafePutPlugin.putOrdered(kind)); } if (kind != JavaKind.Boolean && kind != JavaKind.Object) { // Raw accesses to memory addresses @@ -693,15 +693,29 @@ public class StandardGraphBuilderPlugins { public static class UnsafePutPlugin implements InvocationPlugin { private final JavaKind kind; - private final boolean isVolatile; + private final boolean hasBarrier; + private final int preWrite; + private final int postWrite; public UnsafePutPlugin(JavaKind kind, boolean isVolatile) { + this(kind, isVolatile, JMM_PRE_VOLATILE_WRITE, JMM_POST_VOLATILE_WRITE); + } + + private UnsafePutPlugin(JavaKind kind, boolean hasBarrier, int preWrite, int postWrite) { + super(); this.kind = kind; - this.isVolatile = isVolatile; + this.hasBarrier = hasBarrier; + this.preWrite = preWrite; + this.postWrite = postWrite; + } + + public static UnsafePutPlugin putOrdered(JavaKind kind) { + return new UnsafePutPlugin(kind, true, LOAD_STORE | STORE_STORE, 0); } @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { + assert !hasBarrier : "Barriers for address based Unsafe put is not supported."; // Emits a null-check for the otherwise unused receiver unsafe.get(); b.add(new UnsafeMemoryStoreNode(address, value, kind, OFF_HEAP_LOCATION)); @@ -713,13 +727,13 @@ public class StandardGraphBuilderPlugins { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { // Emits a null-check for the otherwise unused receiver unsafe.get(); - if (isVolatile) { - b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); + if (hasBarrier) { + b.add(new MembarNode(preWrite)); } LocationIdentity locationIdentity = object.isNullConstant() ? OFF_HEAP_LOCATION : LocationIdentity.any(); b.add(new RawStoreNode(object, offset, value, kind, locationIdentity)); - if (isVolatile) { - b.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); + if (hasBarrier) { + b.add(new MembarNode(postWrite)); } b.getGraph().markUnsafeAccess(); return true; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java index f3d9ea9faed..1ccb62eef64 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java @@ -22,19 +22,16 @@ */ package org.graalvm.compiler.replacements.classfile; -import static org.graalvm.compiler.serviceprovider.JDK9Method.getModule; -import static org.graalvm.compiler.serviceprovider.JDK9Method.getResourceAsStream; - import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; -import org.graalvm.compiler.serviceprovider.JDK9Method; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -98,20 +95,6 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider { return false; } - private static InputStream getClassfileAsStream(Class c) { - String classfilePath = c.getName().replace('.', '/') + ".class"; - if (JDK9Method.JAVA_SPECIFICATION_VERSION >= 9) { - Object module = getModule(c); - return getResourceAsStream(module, classfilePath); - } else { - ClassLoader cl = c.getClassLoader(); - if (cl == null) { - return ClassLoader.getSystemResourceAsStream(classfilePath); - } - return cl.getResourceAsStream(classfilePath); - } - } - /** * Gets a {@link Classfile} created by parsing the class file bytes for {@code c}. * @@ -123,7 +106,7 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider { if (classfile == null) { try { ResolvedJavaType type = metaAccess.lookupJavaType(c); - InputStream in = getClassfileAsStream(c); + InputStream in = GraalServices.getClassfileAsStream(c); if (in != null) { DataInputStream stream = new DataInputStream(in); classfile = new Classfile(type, stream, this); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/D b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/D new file mode 100644 index 00000000000..945a643ce98 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/D @@ -0,0 +1,102 @@ +diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java +index 88403c3..728297d 100644 +--- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java ++++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java +@@ -138,7 +138,11 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider { + return classfile; + } + +- synchronized Class resolveToClass(String descriptor) { ++ Class resolveToClass(String descriptor) { ++ return resolveToClass(descriptor, false); ++ } ++ ++ synchronized Class resolveToClass(String descriptor, boolean initialize) { + Class c = classes.get(descriptor); + if (c == null) { + if (descriptor.length() == 1) { +@@ -155,7 +159,7 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider { + name = descriptor.replace('/', '.'); + } + try { +- c = Class.forName(name, true, loader); ++ c = Class.forName(name, initialize, loader); + classes.put(descriptor, c); + } catch (ClassNotFoundException e) { + throw new NoClassDefFoundError(descriptor); +diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java +index 087f78b..bde2dd4 100644 +--- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java ++++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java +@@ -70,8 +70,9 @@ abstract class ClassfileConstant { + * @param cp + * @param index + * @param opcode ++ * @param initialize + */ +- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) { ++ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) { + } + + @Override +@@ -90,15 +91,19 @@ abstract class ClassfileConstant { + } + + @Override +- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) { +- resolve(cp); ++ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) { ++ resolve(cp, initialize); + } + + public ResolvedJavaType resolve(ClassfileConstantPool cp) throws GraalError { ++ return resolve(cp, false /* initialize */); ++ } ++ ++ public ResolvedJavaType resolve(ClassfileConstantPool cp, boolean initialize) throws GraalError { + if (type == null) { + String typeDescriptor = cp.get(Utf8.class, nameIndex).value; + ClassfileBytecodeProvider context = cp.context; +- type = context.metaAccess.lookupJavaType(context.resolveToClass(typeDescriptor)); ++ type = context.metaAccess.lookupJavaType(context.resolveToClass(typeDescriptor, initialize)); + } + return type; + } +@@ -116,8 +121,8 @@ abstract class ClassfileConstant { + } + + @Override +- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) { +- cp.get(ClassRef.class, classIndex).loadReferencedType(cp, classIndex, opcode); ++ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) { ++ cp.get(ClassRef.class, classIndex).loadReferencedType(cp, classIndex, opcode, initialize); + } + } + +@@ -269,7 +274,7 @@ abstract class ClassfileConstant { + } + + @Override +- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) { ++ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) { + throw new GraalError("Resolution of " + name + " constant pool entries not supported by " + ClassfileBytecodeProvider.class.getSimpleName()); + } + } +diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java +index 218df10..a54779b 100644 +--- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java ++++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java +@@ -133,11 +133,11 @@ class ClassfileConstantPool implements ConstantPool { + } + + @Override +- public void loadReferencedType(int index, int opcode) { ++ public void loadReferencedType(int index, int opcode, boolean initialize) { + if (opcode == Bytecodes.INVOKEDYNAMIC) { + throw new GraalError("INVOKEDYNAMIC not supported by " + ClassfileBytecodeProvider.class.getSimpleName()); + } +- entries[index].loadReferencedType(this, index, opcode); ++ entries[index].loadReferencedType(this, index, opcode, initialize); + } + + @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java index f290b2494fb..8a837e98368 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java @@ -44,7 +44,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java index 9f62f4d66bb..de9652f7d2f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java @@ -46,7 +46,7 @@ import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java index a8c9eca51f7..379bb109105 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.replacements.nodes; import static org.graalvm.compiler.nodeinfo.InputType.Memory; import static org.graalvm.compiler.nodeinfo.InputType.State; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.DebugContext; @@ -51,7 +51,7 @@ import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java index 9372e31edfc..35c84c3e759 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java @@ -189,7 +189,7 @@ public abstract class MacroNode extends FixedWithNextNode implements Lowerable, ((Lowerable) nonNullReceiver).lower(tool); } } - InliningUtil.inline(invoke, replacementGraph, false, targetMethod); + InliningUtil.inline(invoke, replacementGraph, false, targetMethod, "Replace with graph.", "LoweringPhase"); replacementGraph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph(), "After inlining replacement %s", replacementGraph); } else { if (isPlaceholderBci(invoke.bci())) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java index 08535f3f95c..7167ec13c98 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.ResolvedJavaMethod; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java index 7821191c735..f187a67866a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java @@ -22,53 +22,44 @@ */ package org.graalvm.compiler.serviceprovider; -import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; -import static org.graalvm.compiler.serviceprovider.JDK9Method.addOpens; -import static org.graalvm.compiler.serviceprovider.JDK9Method.getModule; -import static org.graalvm.compiler.serviceprovider.JDK9Method.getPackages; -import static org.graalvm.compiler.serviceprovider.JDK9Method.isOpenTo; +import static java.lang.Thread.currentThread; -import java.lang.reflect.Method; +import java.io.IOException; +import java.io.InputStream; import java.util.Iterator; +import java.util.List; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; -import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; import jdk.vm.ci.services.JVMCIPermission; import jdk.vm.ci.services.Services; /** - * A mechanism for accessing service providers that abstracts over whether Graal is running on - * JVMCI-8 or JVMCI-9. In JVMCI-8, a JVMCI specific mechanism is used to lookup services via the - * hidden JVMCI class loader. In JVMCI-9, the standard {@link ServiceLoader} mechanism is used. + * Interface to functionality that abstracts over which JDK version Graal is running on. */ public final class GraalServices { - private GraalServices() { + private static int getJavaSpecificationVersion() { + String value = System.getProperty("java.specification.version"); + if (value.startsWith("1.")) { + value = value.substring(2); + } + return Integer.parseInt(value); } /** - * Opens all JVMCI packages to the module of a given class. This relies on JVMCI already having - * opened all its packages to the module defining {@link GraalServices}. - * - * @param other all JVMCI packages will be opened to the module defining this class + * The integer value corresponding to the value of the {@code java.specification.version} system + * property after any leading {@code "1."} has been stripped. */ - public static void openJVMCITo(Class other) { - Object jvmci = getModule(Services.class); - Object otherModule = getModule(other); - if (jvmci != otherModule) { - Set packages = getPackages(jvmci); - for (String pkg : packages) { - boolean opened = isOpenTo(jvmci, pkg, otherModule); - if (!opened) { - try { - addOpens.invoke(jvmci, pkg, otherModule); - } catch (Throwable throwable) { - throw new InternalError(throwable); - } - } - } - } + public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion(); + + /** + * Determines if the Java runtime is version 8 or earlier. + */ + public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8; + + private GraalServices() { } /** @@ -79,15 +70,12 @@ public final class GraalServices { */ public static Iterable load(Class service) { assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName(); - if (Java8OrEarlier) { - return load8(service); - } Iterable iterable = ServiceLoader.load(service); - return new Iterable() { + return new Iterable<>() { @Override public Iterator iterator() { Iterator iterator = iterable.iterator(); - return new Iterator() { + return new Iterator<>() { @Override public boolean hasNext() { return iterator.hasNext(); @@ -111,19 +99,20 @@ public final class GraalServices { } /** - * {@code Services.load(Class)} is only defined in JVMCI-8. + * Opens all JVMCI packages to the module of a given class. This relies on JVMCI already having + * opened all its packages to the module defining {@link GraalServices}. + * + * @param other all JVMCI packages will be opened to the module defining this class */ - private static volatile Method loadMethod; - - @SuppressWarnings("unchecked") - private static Iterable load8(Class service) throws InternalError { - try { - if (loadMethod == null) { - loadMethod = Services.class.getMethod("load", Class.class); + static void openJVMCITo(Class other) { + Module jvmciModule = JVMCI_MODULE; + Module otherModule = other.getModule(); + if (jvmciModule != otherModule) { + for (String pkg : jvmciModule.getPackages()) { + if (!jvmciModule.isOpen(pkg, otherModule)) { + jvmciModule.addOpens(pkg, otherModule); + } } - return (Iterable) loadMethod.invoke(null, service); - } catch (Exception e) { - throw new InternalError(e); } } @@ -159,4 +148,185 @@ public final class GraalServices { } return singleProvider; } + + /** + * Gets the class file bytes for {@code c}. + */ + public static InputStream getClassfileAsStream(Class c) throws IOException { + String classfilePath = c.getName().replace('.', '/') + ".class"; + return c.getModule().getResourceAsStream(classfilePath); + } + + private static final Module JVMCI_MODULE = Services.class.getModule(); + + /** + * A JVMCI package dynamically exported to trusted modules. + */ + private static final String JVMCI_RUNTIME_PACKAGE = "jdk.vm.ci.runtime"; + static { + assert JVMCI_MODULE.getPackages().contains(JVMCI_RUNTIME_PACKAGE); + } + + /** + * Determines if invoking {@link Object#toString()} on an instance of {@code c} will only run + * trusted code. + */ + public static boolean isToStringTrusted(Class c) { + Module module = c.getModule(); + Module jvmciModule = JVMCI_MODULE; + assert jvmciModule.getPackages().contains("jdk.vm.ci.runtime"); + if (module == jvmciModule || jvmciModule.isOpen(JVMCI_RUNTIME_PACKAGE, module)) { + // Can access non-statically-exported package in JVMCI + return true; + } + return false; + } + + /** + * Gets a unique identifier for this execution such as a process ID or a + * {@linkplain #getGlobalTimeStamp() fixed timestamp}. + */ + public static String getExecutionID() { + return Long.toString(ProcessHandle.current().pid()); + } + + private static final AtomicLong globalTimeStamp = new AtomicLong(); + + /** + * Gets a time stamp for the current process. This method will always return the same value for + * the current VM execution. + */ + public static long getGlobalTimeStamp() { + if (globalTimeStamp.get() == 0) { + globalTimeStamp.compareAndSet(0, System.currentTimeMillis()); + } + return globalTimeStamp.get(); + } + + /** + * Access to thread specific information made available via Java Management Extensions (JMX). + * Using this abstraction enables avoiding a dependency to the {@code java.management} and + * {@code jdk.management} modules on JDK 9 and later. + */ + public abstract static class JMXService { + protected abstract long getThreadAllocatedBytes(long id); + + protected abstract long getCurrentThreadCpuTime(); + + protected abstract boolean isThreadAllocatedMemorySupported(); + + protected abstract boolean isCurrentThreadCpuTimeSupported(); + + protected abstract List getInputArguments(); + + // Placing this static field in JMXService (instead of GraalServices) + // allows for lazy initialization. + static final JMXService instance = loadSingle(JMXService.class, false); + } + + /** + * Returns an approximation of the total amount of memory, in bytes, allocated in heap memory + * for the thread of the specified ID. The returned value is an approximation because some Java + * virtual machine implementations may use object allocation mechanisms that result in a delay + * between the time an object is allocated and the time its size is recorded. + *

+ * If the thread of the specified ID is not alive or does not exist, this method returns + * {@code -1}. If thread memory allocation measurement is disabled, this method returns + * {@code -1}. A thread is alive if it has been started and has not yet died. + *

+ * If thread memory allocation measurement is enabled after the thread has started, the Java + * virtual machine implementation may choose any time up to and including the time that the + * capability is enabled as the point where thread memory allocation measurement starts. + * + * @param id the thread ID of a thread + * @return an approximation of the total memory allocated, in bytes, in heap memory for a thread + * of the specified ID if the thread of the specified ID exists, the thread is alive, + * and thread memory allocation measurement is enabled; {@code -1} otherwise. + * + * @throws IllegalArgumentException if {@code id} {@code <=} {@code 0}. + * @throws UnsupportedOperationException if the Java virtual machine implementation does not + * {@linkplain #isThreadAllocatedMemorySupported() support} thread memory allocation + * measurement. + */ + public static long getThreadAllocatedBytes(long id) { + JMXService jmx = JMXService.instance; + if (jmx == null) { + throw new UnsupportedOperationException(); + } + return jmx.getThreadAllocatedBytes(id); + } + + /** + * Convenience method for calling {@link #getThreadAllocatedBytes(long)} with the id of the + * current thread. + */ + public static long getCurrentThreadAllocatedBytes() { + return getThreadAllocatedBytes(currentThread().getId()); + } + + /** + * Returns the total CPU time for the current thread in nanoseconds. The returned value is of + * nanoseconds precision but not necessarily nanoseconds accuracy. If the implementation + * distinguishes between user mode time and system mode time, the returned CPU time is the + * amount of time that the current thread has executed in user mode or system mode. + * + * @return the total CPU time for the current thread if CPU time measurement is enabled; + * {@code -1} otherwise. + * + * @throws UnsupportedOperationException if the Java virtual machine does not + * {@linkplain #isCurrentThreadCpuTimeSupported() support} CPU time measurement for + * the current thread + */ + public static long getCurrentThreadCpuTime() { + JMXService jmx = JMXService.instance; + if (jmx == null) { + throw new UnsupportedOperationException(); + } + return jmx.getCurrentThreadCpuTime(); + } + + /** + * Determines if the Java virtual machine implementation supports thread memory allocation + * measurement. + */ + public static boolean isThreadAllocatedMemorySupported() { + JMXService jmx = JMXService.instance; + if (jmx == null) { + return false; + } + return jmx.isThreadAllocatedMemorySupported(); + } + + /** + * Determines if the Java virtual machine supports CPU time measurement for the current thread. + */ + public static boolean isCurrentThreadCpuTimeSupported() { + JMXService jmx = JMXService.instance; + if (jmx == null) { + return false; + } + return jmx.isCurrentThreadCpuTimeSupported(); + } + + /** + * Gets the input arguments passed to the Java virtual machine which does not include the + * arguments to the {@code main} method. This method returns an empty list if there is no input + * argument to the Java virtual machine. + *

+ * Some Java virtual machine implementations may take input arguments from multiple different + * sources: for examples, arguments passed from the application that launches the Java virtual + * machine such as the 'java' command, environment variables, configuration files, etc. + *

+ * Typically, not all command-line options to the 'java' command are passed to the Java virtual + * machine. Thus, the returned input arguments may not include all command-line options. + * + * @return the input arguments to the JVM or {@code null} if they are unavailable + */ + public static List getInputArguments() { + JMXService jmx = JMXService.instance; + if (jmx == null) { + return null; + } + return jmx.getInputArguments(); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java deleted file mode 100644 index e8eb639db2b..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.serviceprovider; - -import java.io.InputStream; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Method; -import java.util.Set; - -/** - * Reflection based access to API introduced by JDK 9. This allows the API to be used in code that - * must be compiled on a JDK prior to 9. - */ -public final class JDK9Method { - - private static int getJavaSpecificationVersion() { - String value = System.getProperty("java.specification.version"); - if (value.startsWith("1.")) { - value = value.substring(2); - } - return Integer.parseInt(value); - } - - /** - * The integer value corresponding to the value of the {@code java.specification.version} system - * property after any leading {@code "1."} has been stripped. - */ - public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion(); - - public static MethodHandle lookupMethodHandle(Class declaringClass, String name, Class... parameterTypes) { - try { - return MethodHandles.lookup().unreflect(declaringClass.getMethod(name, parameterTypes)); - } catch (Exception e) { - throw new InternalError(e); - } - } - - private static Method lookupMethod(Class declaringClass, String name, Class... parameterTypes) { - try { - return declaringClass.getMethod(name, parameterTypes); - } catch (Exception e) { - throw new InternalError(e); - } - } - - /** - * Determines if the Java runtime is version 8 or earlier. - */ - public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8; - - /** - * {@code Class.getModule()}. - */ - private static final MethodHandle getModuleHandle; - - public static Object getModule(Class clazz) { - try { - return getModuleHandle.invoke(clazz); - } catch (Throwable throwable) { - throw new InternalError(throwable); - } - } - - /** - * {@code java.lang.Module.getPackages()}. - */ - private static final MethodHandle getPackages; - - public static Set getPackages(Object module) { - try { - return (Set) getPackages.invoke(module); - } catch (Throwable throwable) { - throw new InternalError(throwable); - } - } - - /** - * {@code java.lang.Module.getResourceAsStream(String)}. - */ - private static final MethodHandle getResourceAsStream; - - public static InputStream getResourceAsStream(Object module, String resource) { - try { - return (InputStream) getResourceAsStream.invoke(module, resource); - } catch (Throwable throwable) { - throw new InternalError(throwable); - } - } - - /** - * {@code java.lang.Module.addOpens(String, Module)}. This only seems to work correctly when - * invoked through reflection. - */ - public static final Method addOpens; - - /** - * {@code java.lang.Module.isOpen(String, Module)}. - */ - private static final MethodHandle isOpenTo; - - public static boolean isOpenTo(Object module1, String pkg, Object module2) { - try { - return (boolean) isOpenTo.invoke(module1, pkg, module2); - } catch (Throwable throwable) { - throw new InternalError(throwable); - } - } - - public static final Class MODULE_CLASS; - - static { - if (JAVA_SPECIFICATION_VERSION >= 9) { - try { - MODULE_CLASS = Class.class.getMethod("getModule").getReturnType(); - getModuleHandle = lookupMethodHandle(Class.class, "getModule"); - getPackages = lookupMethodHandle(MODULE_CLASS, "getPackages"); - addOpens = lookupMethod(MODULE_CLASS, "addOpens", String.class, MODULE_CLASS); - getResourceAsStream = lookupMethodHandle(MODULE_CLASS, "getResourceAsStream", String.class); - isOpenTo = lookupMethodHandle(MODULE_CLASS, "isOpen", String.class, MODULE_CLASS); - } catch (NoSuchMethodException e) { - throw new InternalError(e); - } - } else { - MODULE_CLASS = null; - getModuleHandle = null; - getPackages = null; - addOpens = null; - getResourceAsStream = null; - isOpenTo = null; - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java index 06f1e7ae9af..d4cd7e567df 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java @@ -40,6 +40,7 @@ import org.graalvm.compiler.debug.DebugDumpHandler; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.GlobalMetrics; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GraalServices; import org.junit.After; import org.junit.Assert; import org.junit.internal.ComparisonCriteria; @@ -64,7 +65,7 @@ public class GraalTest { } } - public static final boolean Java8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0; + public static final boolean Java8OrEarlier = GraalServices.Java8OrEarlier; protected Method getMethod(String methodName) { return getMethod(getClass(), methodName); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java index 83c5ebcc45f..f57b0457d00 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java @@ -35,6 +35,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.util.CollectionsUtil; /** @@ -236,7 +237,7 @@ public final class SubprocessUtil { return new Subprocess(command, process.waitFor(), output); } - private static final boolean isJava8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0; + private static final boolean isJava8OrEarlier = GraalServices.Java8OrEarlier; private static boolean hasArg(String optionName) { if (optionName.equals("-cp") || optionName.equals("-classpath")) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude deleted file mode 100644 index 2ba488104ee..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual.bench/.checkstyle.exclude +++ /dev/null @@ -1 +0,0 @@ -src_gen diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java index 12eebb38eff..3fdabfee40d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java @@ -25,8 +25,8 @@ package org.graalvm.compiler.virtual.phases.ea; import java.util.Iterator; import java.util.Map; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.UnmodifiableMapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; public abstract class EffectsBlockState> { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java index b005b85e617..6382c81dd92 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java @@ -25,9 +25,9 @@ package org.graalvm.compiler.virtual.phases.ea; import java.util.ArrayList; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.Stamp; @@ -62,7 +62,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.LoopInfo; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; public abstract class EffectsClosure> extends EffectsPhase.Closure { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java index 34860543551..e7ed6682ae2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.virtual.phases.ea; import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.core.common.util.CompilationAlarm; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Graph.NodeEventScope; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java index b934abe3aad..d9bafaaf08a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java @@ -25,8 +25,8 @@ package org.graalvm.compiler.virtual.phases.ea; import java.util.Iterator; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugContext; @@ -37,7 +37,7 @@ import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java index ab0551dbc17..fd3792febe4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java @@ -29,11 +29,11 @@ import java.util.EnumMap; import java.util.Iterator; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; -import org.graalvm.collections.Pair; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; +import jdk.internal.vm.compiler.collections.Pair; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.graph.Node; @@ -66,7 +66,7 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java index a51af3e4e11..92c1e93c20c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java @@ -28,9 +28,9 @@ import java.util.Iterator; import java.util.List; import java.util.function.IntUnaryOperator; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java index a911e59e215..c629f548e18 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java @@ -25,7 +25,7 @@ package org.graalvm.compiler.virtual.phases.ea; import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalysisIterations; import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalyzeOnly; -import org.graalvm.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java index 14dc07883c7..a7f7dca0b52 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java @@ -24,10 +24,10 @@ package org.graalvm.compiler.virtual.phases.ea; import java.util.Iterator; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; /** * This class maintains a set of known values, identified by base object, locations and offset. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java index 7f23c16771e..ded9cd547d9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java @@ -23,15 +23,15 @@ package org.graalvm.compiler.virtual.phases.ea; import static org.graalvm.compiler.core.common.GraalOptions.ReadEliminationMaxLoopVisits; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.util.Iterator; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; -import org.graalvm.collections.Equivalence; -import org.graalvm.collections.MapCursor; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import jdk.internal.vm.compiler.collections.MapCursor; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; @@ -63,7 +63,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.UnsafeLoadCacheEntry; -import org.graalvm.word.LocationIdentity; +import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaType; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java index 83223b5f1d1..ce947a576d0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java @@ -26,8 +26,8 @@ import static org.graalvm.compiler.core.common.GraalOptions.TraceEscapeAnalysis; import java.util.List; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TTY; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java index 0aecb65e1e2..8db659ef1ad 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java @@ -24,11 +24,11 @@ package org.graalvm.compiler.word; import org.graalvm.compiler.word.Word.Opcode; import org.graalvm.compiler.word.Word.Operation; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.SignedWord; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordBase; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.SignedWord; +import jdk.internal.vm.compiler.word.UnsignedWord; +import jdk.internal.vm.compiler.word.WordBase; /** * Medium-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java index 2f245a4362e..9933fa31837 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java @@ -24,11 +24,11 @@ package org.graalvm.compiler.word; import org.graalvm.compiler.word.Word.Opcode; import org.graalvm.compiler.word.Word.Operation; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.SignedWord; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordBase; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.SignedWord; +import jdk.internal.vm.compiler.word.UnsignedWord; +import jdk.internal.vm.compiler.word.WordBase; /** * Low-level memory access for Objects. Similarly to the readXxx and writeXxx methods defined for diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java index 21dc91ba3d2..8a790cb70e9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java @@ -48,19 +48,19 @@ import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; import org.graalvm.compiler.nodes.calc.XorNode; import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; import org.graalvm.compiler.nodes.memory.address.AddressNode.Address; -import org.graalvm.word.ComparableWord; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; -import org.graalvm.word.SignedWord; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordBase; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.ComparableWord; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; +import jdk.internal.vm.compiler.word.SignedWord; +import jdk.internal.vm.compiler.word.UnsignedWord; +import jdk.internal.vm.compiler.word.WordBase; +import jdk.internal.vm.compiler.word.WordFactory; +import jdk.internal.vm.compiler.word.impl.WordBoxFactory; -public abstract class Word extends WordFactory implements SignedWord, UnsignedWord, Pointer { +public abstract class Word implements SignedWord, UnsignedWord, Pointer { static { - assert WordFactory.boxFactory == null : "BoxFactory must be initialized only once."; - WordFactory.boxFactory = new BoxFactoryImpl(); + BoxFactoryImpl.initialize(); } public static void ensureInitialized() { @@ -109,10 +109,15 @@ public abstract class Word extends WordFactory implements SignedWord, UnsignedWo TO_RAW_VALUE, } - public static class BoxFactoryImpl implements BoxFactory { + static class BoxFactoryImpl extends WordBoxFactory { + static void initialize() { + assert boxFactory == null : "BoxFactory must be initialized only once."; + boxFactory = new BoxFactoryImpl(); + } + @SuppressWarnings("unchecked") @Override - public T box(long val) { + public T boxImpl(long val) { return (T) HostedWord.boxLong(val); } } @@ -697,55 +702,55 @@ public abstract class Word extends WordFactory implements SignedWord, UnsignedWo @Override @Operation(opcode = Opcode.READ_POINTER) public byte readByte(int offset, LocationIdentity locationIdentity) { - return readByte(signed(offset), locationIdentity); + return readByte(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public char readChar(int offset, LocationIdentity locationIdentity) { - return readChar(signed(offset), locationIdentity); + return readChar(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public short readShort(int offset, LocationIdentity locationIdentity) { - return readShort(signed(offset), locationIdentity); + return readShort(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public int readInt(int offset, LocationIdentity locationIdentity) { - return readInt(signed(offset), locationIdentity); + return readInt(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public long readLong(int offset, LocationIdentity locationIdentity) { - return readLong(signed(offset), locationIdentity); + return readLong(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public float readFloat(int offset, LocationIdentity locationIdentity) { - return readFloat(signed(offset), locationIdentity); + return readFloat(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public double readDouble(int offset, LocationIdentity locationIdentity) { - return readDouble(signed(offset), locationIdentity); + return readDouble(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public T readWord(int offset, LocationIdentity locationIdentity) { - return readWord(signed(offset), locationIdentity); + return readWord(WordFactory.signed(offset), locationIdentity); } @Override @Operation(opcode = Opcode.READ_POINTER) public Object readObject(int offset, LocationIdentity locationIdentity) { - return readObject(signed(offset), locationIdentity); + return readObject(WordFactory.signed(offset), locationIdentity); } @Override @@ -809,61 +814,61 @@ public abstract class Word extends WordFactory implements SignedWord, UnsignedWo @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeByte(int offset, byte val, LocationIdentity locationIdentity) { - writeByte(signed(offset), val, locationIdentity); + writeByte(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeChar(int offset, char val, LocationIdentity locationIdentity) { - writeChar(signed(offset), val, locationIdentity); + writeChar(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeShort(int offset, short val, LocationIdentity locationIdentity) { - writeShort(signed(offset), val, locationIdentity); + writeShort(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeInt(int offset, int val, LocationIdentity locationIdentity) { - writeInt(signed(offset), val, locationIdentity); + writeInt(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeLong(int offset, long val, LocationIdentity locationIdentity) { - writeLong(signed(offset), val, locationIdentity); + writeLong(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeFloat(int offset, float val, LocationIdentity locationIdentity) { - writeFloat(signed(offset), val, locationIdentity); + writeFloat(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeDouble(int offset, double val, LocationIdentity locationIdentity) { - writeDouble(signed(offset), val, locationIdentity); + writeDouble(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeWord(int offset, WordBase val, LocationIdentity locationIdentity) { - writeWord(signed(offset), val, locationIdentity); + writeWord(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.INITIALIZE) public void initializeLong(int offset, long val, LocationIdentity locationIdentity) { - initializeLong(signed(offset), val, locationIdentity); + initializeLong(WordFactory.signed(offset), val, locationIdentity); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeObject(int offset, Object val, LocationIdentity locationIdentity) { - writeObject(signed(offset), val, locationIdentity); + writeObject(WordFactory.signed(offset), val, locationIdentity); } @Override @@ -924,60 +929,60 @@ public abstract class Word extends WordFactory implements SignedWord, UnsignedWo @Override @Operation(opcode = Opcode.READ_POINTER) public byte readByte(int offset) { - return readByte(signed(offset)); + return readByte(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public char readChar(int offset) { - return readChar(signed(offset)); + return readChar(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public short readShort(int offset) { - return readShort(signed(offset)); + return readShort(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public int readInt(int offset) { - return readInt(signed(offset)); + return readInt(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public long readLong(int offset) { - return readLong(signed(offset)); + return readLong(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public float readFloat(int offset) { - return readFloat(signed(offset)); + return readFloat(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public double readDouble(int offset) { - return readDouble(signed(offset)); + return readDouble(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public T readWord(int offset) { - return readWord(signed(offset)); + return readWord(WordFactory.signed(offset)); } @Override @Operation(opcode = Opcode.READ_POINTER) public Object readObject(int offset) { - return readObject(signed(offset)); + return readObject(WordFactory.signed(offset)); } @Operation(opcode = Opcode.READ_HEAP) public Object readObject(int offset, BarrierType barrierType) { - return readObject(signed(offset), barrierType); + return readObject(WordFactory.signed(offset), barrierType); } @Override @@ -1073,103 +1078,103 @@ public abstract class Word extends WordFactory implements SignedWord, UnsignedWo @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeByte(int offset, byte val) { - writeByte(signed(offset), val); + writeByte(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeChar(int offset, char val) { - writeChar(signed(offset), val); + writeChar(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeShort(int offset, short val) { - writeShort(signed(offset), val); + writeShort(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeInt(int offset, int val) { - writeInt(signed(offset), val); + writeInt(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeLong(int offset, long val) { - writeLong(signed(offset), val); + writeLong(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeFloat(int offset, float val) { - writeFloat(signed(offset), val); + writeFloat(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeDouble(int offset, double val) { - writeDouble(signed(offset), val); + writeDouble(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeWord(int offset, WordBase val) { - writeWord(signed(offset), val); + writeWord(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.WRITE_POINTER) public void writeObject(int offset, Object val) { - writeObject(signed(offset), val); + writeObject(WordFactory.signed(offset), val); } @Override @Operation(opcode = Opcode.CAS_POINTER) public int compareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity) { - return compareAndSwapInt(signed(offset), expectedValue, newValue, locationIdentity); + return compareAndSwapInt(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public long compareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity) { - return compareAndSwapLong(signed(offset), expectedValue, newValue, locationIdentity); + return compareAndSwapLong(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public T compareAndSwapWord(int offset, T expectedValue, T newValue, LocationIdentity locationIdentity) { - return compareAndSwapWord(signed(offset), expectedValue, newValue, locationIdentity); + return compareAndSwapWord(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public Object compareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity) { - return compareAndSwapObject(signed(offset), expectedValue, newValue, locationIdentity); + return compareAndSwapObject(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public boolean logicCompareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity) { - return logicCompareAndSwapInt(signed(offset), expectedValue, newValue, locationIdentity); + return logicCompareAndSwapInt(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public boolean logicCompareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity) { - return logicCompareAndSwapLong(signed(offset), expectedValue, newValue, locationIdentity); + return logicCompareAndSwapLong(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public boolean logicCompareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity) { - return logicCompareAndSwapWord(signed(offset), expectedValue, newValue, locationIdentity); + return logicCompareAndSwapWord(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } @Override @Operation(opcode = Opcode.CAS_POINTER) public boolean logicCompareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity) { - return logicCompareAndSwapObject(signed(offset), expectedValue, newValue, locationIdentity); + return logicCompareAndSwapObject(WordFactory.signed(offset), expectedValue, newValue, locationIdentity); } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java index 2d5f5a9145d..94971d79960 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.word; import static org.graalvm.compiler.nodes.ConstantNode.forInt; import static org.graalvm.compiler.nodes.ConstantNode.forIntegerKind; -import static org.graalvm.word.LocationIdentity.any; +import static jdk.internal.vm.compiler.word.LocationIdentity.any; import java.lang.reflect.Constructor; import java.util.Arrays; @@ -70,8 +70,8 @@ import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.word.Word.Opcode; import org.graalvm.compiler.word.Word.Operation; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.impl.WordFactoryOperation; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.JavaKind; @@ -85,7 +85,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; * A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that * need special handling for {@link Word} types. */ -public class WordOperationPlugin extends WordFactory implements NodePlugin, TypePlugin, InlineInvokePlugin { +public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvokePlugin { protected final WordTypes wordTypes; protected final JavaKind wordKind; protected final SnippetReflectionProvider snippetReflection; @@ -175,14 +175,14 @@ public class WordOperationPlugin extends WordFactory implements NodePlugin, Type } protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) { - return new LoadIndexedNode(null, array, index, wordTypes.getWordKind()); + return new LoadIndexedNode(null, array, index, wordKind); } @Override public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { if (field.getJavaKind() == JavaKind.Object) { boolean isWordField = wordTypes.isWord(field.getType()); - boolean isWordValue = value.getStackKind() == wordTypes.getWordKind(); + boolean isWordValue = value.getStackKind() == wordKind; if (isWordField && !isWordValue) { throw bailout(b, "Cannot store a non-word value into a word field: " + field.format("%H.%n")); @@ -205,20 +205,20 @@ public class WordOperationPlugin extends WordFactory implements NodePlugin, Type ResolvedJavaType arrayType = StampTool.typeOrNull(array); if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) { assert elementKind == JavaKind.Object; - if (value.getStackKind() != wordTypes.getWordKind()) { + if (value.getStackKind() != wordKind) { throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true)); } b.add(createStoreIndexedNode(array, index, value)); return true; } - if (elementKind == JavaKind.Object && value.getStackKind() == wordTypes.getWordKind()) { + if (elementKind == JavaKind.Object && value.getStackKind() == wordKind) { throw bailout(b, "Cannot store a word value into a non-word array: " + arrayType.toJavaName(true)); } return false; } protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) { - return new StoreIndexedNode(array, index, wordTypes.getWordKind(), value); + return new StoreIndexedNode(array, index, wordKind, value); } @Override @@ -230,7 +230,7 @@ public class WordOperationPlugin extends WordFactory implements NodePlugin, Type return false; } - if (object.getStackKind() != wordTypes.getWordKind()) { + if (object.getStackKind() != wordKind) { throw bailout(b, "Cannot cast a non-word value to a word type: " + type.toJavaName(true)); } b.push(JavaKind.Object, object); @@ -249,7 +249,7 @@ public class WordOperationPlugin extends WordFactory implements NodePlugin, Type protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalError { JavaKind returnKind = wordMethod.getSignature().getReturnKind(); - WordFactory.FactoryOperation factoryOperation = BridgeMethodUtils.getAnnotation(WordFactory.FactoryOperation.class, wordMethod); + WordFactoryOperation factoryOperation = BridgeMethodUtils.getAnnotation(WordFactoryOperation.class, wordMethod); if (factoryOperation != null) { switch (factoryOperation.opcode()) { case ZERO: @@ -510,10 +510,6 @@ public class WordOperationPlugin extends WordFactory implements NodePlugin, Type } } - public WordTypes getWordTypes() { - return wordTypes; - } - private static BailoutException bailout(GraphBuilderContext b, String msg) { throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci())); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java index 0d81cdf58e6..7771720d3e7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java @@ -27,8 +27,8 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.word.Word.Operation; -import org.graalvm.word.WordBase; -import org.graalvm.word.WordFactory; +import jdk.internal.vm.compiler.word.WordBase; +import jdk.internal.vm.compiler.word.WordFactory; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphElements.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphElements.java index c41492b6f0e..2f46c808ec9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphElements.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphElements.java @@ -187,7 +187,10 @@ public interface GraphElements { int nodeSourcePositionBCI(P pos); /** - * Stack trace element for a method, index and position. + * Stack trace element for a method, index and position. This is the basic version of the method + * that works with {@link StackTraceElement} and is suitable for Java-like languages. Should you + * need to provide more details about the location of multiple strata, see + * {@link GraphLocations} interface that gives more control over the provided location data. * * @param method the method * @param bci the index @@ -195,4 +198,5 @@ public interface GraphElements { * @return stack trace element for the method, index and position */ StackTraceElement methodStackTraceElement(M method, int bci, P pos); + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphLocations.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphLocations.java new file mode 100644 index 00000000000..a07b93473ea --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphLocations.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 org.graalvm.graphio; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Provides source location information about compiled code. This interface is an extension of + * {@link GraphElements} - by default the elements work with classical {@link StackTraceElement}. + * Should the default behavior not be sufficient, feel free to implement the additional operations + * available in this interface and register your implementation when {@link GraphOutput.Builder + * building} the {@link GraphOutput} instance. + * + * @param type representing methods + * @param

type representing source code location + * @param represeting {@link StackTraceElement stack element} location + * + * @since 0.33 part of GraalVM 0.33 + */ +public interface GraphLocations { + /** + * Stack trace element for a method, index and position. Returns all applicable source locations + * for given code position. Each provided location is expected to represent location in a + * different {@link #locationLanguage(java.lang.Object) language}. + * + * @param method the method + * @param bci the index + * @param pos the position + * @return elements representing location for all language strata + */ + Iterable methodLocation(M method, int bci, P pos); + + /** + * Identification of the language. Each location can point to a source in a different language - + * e.g. each location can have multiple strata. + * + * @param location the location + * @return id of the language/strata + */ + String locationLanguage(L location); + + /** + * The universal resource identification that contains the location.If the location can be found + * in an assummably accessible resource, then use such resource identification. It is up to the + * side processing the URI to load the content from the location. Protocols scheme {@code file}, + * {@code http}, or {@code https} are assumed to be accessible. + *

+ * If the location is inside of a virtual source, or source which is unlikely to be accessible + * outside of running program, then it may be better to encode the whole source into the + * resource identifier. This can be done by using + * data + * URIs like: + * + *

+     * data:text/javascript,alert('Vivat graphs!')
+     * 
+ * + * @param location the location + * @return the file name for the given location or {@code null} if it is not known + * @throws URISyntaxException yielding this exception aborts the graph dumping + */ + URI locationURI(L location) throws URISyntaxException; + + /** + * Line number of a location. The first line in the source file is one. Negative value means the + * line location isn't available. In such situation one can provide an offset driven location + * co-ordinates via {@link #locationOffsetStart(java.lang.Object)} and + * {@link #locationOffsetEnd(java.lang.Object)} methods. + * + * @param location the location + * @return the line number for given location, negative value means no line + */ + int locationLineNumber(L location); + + /** + * Offset of the location. In certain situations it is preferrable to specify offset rather than + * {@link #locationLineNumber(java.lang.Object) line number} of a location in source. In such + * case return the start offset from this method and end offset via + * {@link #locationOffsetEnd(java.lang.Object)} method. Offsets are counted from {@code 0}. + * + * @param location the location + * @return the starting offset of the location, negative value means no offset + */ + int locationOffsetStart(L location); + + /** + * Offset of the location. In certain situations it is preferrable to specify offset rather than + * {@link #locationLineNumber(java.lang.Object) line number} of a location in source. In such + * case return the start offset via {@link #locationOffsetStart(java.lang.Object)} method and + * end from this method. Offsets are counted from {@code 0}. + * + * @param location the location + * @return the end offset (exclusive) of the location, negative value means no offset + */ + int locationOffsetEnd(L location); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java index b08671ebd43..18f6cfe0e1f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java @@ -24,7 +24,10 @@ package org.graalvm.graphio; import java.io.Closeable; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.channels.WritableByteChannel; +import java.util.Collections; import java.util.Map; /** @@ -34,9 +37,9 @@ import java.util.Map; * @param the type of methods this instance handles */ public final class GraphOutput implements Closeable { - private final GraphProtocol printer; + private final GraphProtocol printer; - private GraphOutput(GraphProtocol p) { + private GraphOutput(GraphProtocol p) { this.printer = p; } @@ -110,7 +113,8 @@ public final class GraphOutput implements Closeable { */ public static final class Builder { private final GraphStructure structure; - private GraphElements elements = null; + private ElementsAndLocations elementsAndLocations; + private GraphTypes types = DefaultGraphTypes.DEFAULT; private GraphBlocks blocks = DefaultGraphBlocks.empty(); private int major = 4; @@ -164,9 +168,24 @@ public final class GraphOutput implements Closeable { * @param graphElements the elements implementation * @return this builder */ + public Builder elements(GraphElements graphElements) { + StackLocations loc = new StackLocations<>(graphElements); + return elementsAndLocations(graphElements, loc); + } + + /** + * Associates implementation of graph elements and an advanced way to interpret their + * locations. + * + * @param graphElements the elements implementation + * @param graphLocations the locations for the elements + * @return this builder + * @since 0.33 GraalVM 0.33 + */ @SuppressWarnings({"unchecked", "rawtypes"}) - public Builder elements(GraphElements graphElements) { - this.elements = (GraphElements) graphElements; + public Builder elementsAndLocations(GraphElements graphElements, GraphLocations graphLocations) { + ElementsAndLocations both = new ElementsAndLocations<>(graphElements, graphLocations); + this.elementsAndLocations = both; return (Builder) this; } @@ -179,8 +198,7 @@ public final class GraphOutput implements Closeable { * @throws IOException if something goes wrong when writing to the channel */ public GraphOutput build(WritableByteChannel channel) throws IOException { - ProtocolImpl p = new ProtocolImpl<>(major, minor, structure, types, blocks, elements, channel); - return new GraphOutput<>(p); + return buildImpl(elementsAndLocations, channel); } /** @@ -200,8 +218,85 @@ public final class GraphOutput implements Closeable { * @return new output sharing {@code channel} and other internals with {@code parent} */ public GraphOutput build(GraphOutput parent) { - ProtocolImpl p = new ProtocolImpl<>(parent.printer, structure, types, blocks, elements); + return buildImpl(elementsAndLocations, parent); + } + + private GraphOutput buildImpl(ElementsAndLocations e, WritableByteChannel channel) throws IOException { + // @formatter:off + ProtocolImpl p = new ProtocolImpl<>( + major, minor, structure, types, blocks, + e == null ? null : e.elements, + e == null ? null : e.locations, channel + ); + // @formatter:on + return new GraphOutput<>(p); + } + + private GraphOutput buildImpl(ElementsAndLocations e, GraphOutput parent) { + // @formatter:off + ProtocolImpl p = new ProtocolImpl<>( + parent.printer, structure, types, blocks, + e == null ? null : e.elements, + e == null ? null : e.locations + ); + // @formatter:on return new GraphOutput<>(p); } } + + private static final class ElementsAndLocations { + final GraphElements elements; + final GraphLocations locations; + + ElementsAndLocations(GraphElements elements, GraphLocations locations) { + elements.getClass(); + locations.getClass(); + this.elements = elements; + this.locations = locations; + } + } + + private static final class StackLocations implements GraphLocations { + private final GraphElements graphElements; + + StackLocations(GraphElements graphElements) { + this.graphElements = graphElements; + } + + @Override + public Iterable methodLocation(M method, int bci, P pos) { + StackTraceElement ste = this.graphElements.methodStackTraceElement(method, bci, pos); + return Collections.singleton(ste); + } + + @Override + public URI locationURI(StackTraceElement location) { + String path = location.getFileName(); + try { + return path == null ? null : new URI(null, null, path, null); + } catch (URISyntaxException ex) { + throw new IllegalArgumentException(ex); + } + } + + @Override + public int locationLineNumber(StackTraceElement location) { + return location.getLineNumber(); + } + + @Override + public String locationLanguage(StackTraceElement location) { + return "Java"; + } + + @Override + public int locationOffsetStart(StackTraceElement location) { + return -1; + } + + @Override + public int locationOffsetEnd(StackTraceElement location) { + return -1; + } + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java index e0fb0a3f804..c437c7cc2d7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java @@ -24,16 +24,20 @@ package org.graalvm.graphio; import java.io.Closeable; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; +import java.util.Objects; -abstract class GraphProtocol implements Closeable { +abstract class GraphProtocol implements Closeable { private static final Charset UTF8 = Charset.forName("UTF-8"); private static final int CONSTANT_POOL_MAX_SIZE = 8000; @@ -76,7 +80,7 @@ abstract class GraphProtocol 5 || (major == 5 && minor > 0)) { + if (major > 6 || (major == 6 && minor > 0)) { throw new IllegalArgumentException("Unrecognized version " + major + "." + minor); } this.versionMajor = major; @@ -87,7 +91,7 @@ abstract class GraphProtocol parent) { + GraphProtocol(GraphProtocol parent) { this.versionMajor = parent.versionMajor; this.versionMinor = parent.versionMinor; this.constantPool = parent.constantPool; @@ -254,7 +258,19 @@ abstract class GraphProtocol findLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos); + + protected abstract String findLocationFile(Location loc) throws IOException; + + protected abstract int findLocationLine(Location loc); + + protected abstract URI findLocationURI(Location loc) throws URISyntaxException; + + protected abstract String findLocationLanguage(Location loc); + + protected abstract int findLocationStart(Location loc); + + protected abstract int findLocationEnd(Location loc); private void writeVersion() throws IOException { writeBytesRaw(MAGIC_BYTES); @@ -374,34 +390,57 @@ abstract class GraphProtocol= 4 && findNodeSourcePosition(object) != null) { - writeByte(POOL_NODE_SOURCE_POSITION); - } else { - final Node node = findNode(object); - if (versionMajor == 4 && node != null) { - object = classForNode(node); + int type = findPoolType(object, null); + writeByte(type); + writeShort(id.charValue()); + } + } + + private int findPoolType(Object obj, Object[] found) throws IOException { + Object object = obj; + if (object == null) { + return POOL_NULL; + } + if (isFound(findJavaField(object), found)) { + return POOL_FIELD; + } else if (isFound(findSignature(object), found)) { + return POOL_SIGNATURE; + } else if (versionMajor >= 4 && isFound(findNodeSourcePosition(object), found)) { + return POOL_NODE_SOURCE_POSITION; + } else { + final Node node = findNode(object); + if (versionMajor == 4 && node != null) { + object = classForNode(node); + } + if (isFound(findNodeClass(object), found)) { + return POOL_NODE_CLASS; + } else if (versionMajor >= 5 && isFound(node, found)) { + return POOL_NODE; + } else if (isFound(findMethod(object), found)) { + return POOL_METHOD; + } else if (object instanceof Enum) { + if (found != null) { + found[0] = ((Enum) object).ordinal(); } - if (findNodeClass(object) != null) { - writeByte(POOL_NODE_CLASS); - } else if (versionMajor >= 5 && node != null) { - writeByte(POOL_NODE); - } else if (findMethod(object) != null) { - writeByte(POOL_METHOD); - } else { - if (object instanceof Enum || findEnumOrdinal(object) >= 0) { - writeByte(POOL_ENUM); - } else if (object instanceof Class || findJavaTypeName(object) != null) { - writeByte(POOL_CLASS); - } else { - writeByte(POOL_STRING); + return POOL_ENUM; + } else { + int val = findEnumOrdinal(object); + if (val >= 0) { + if (found != null) { + found[0] = val; } + return POOL_ENUM; + } else if (object instanceof Class) { + if (found != null) { + found[0] = ((Class) object).getName(); + } + return POOL_CLASS; + } else if (isFound(findJavaTypeName(object), found)) { + return POOL_CLASS; + } else { + return POOL_STRING; } } - writeShort(id.charValue()); } } @@ -519,61 +558,89 @@ abstract class GraphProtocol= 4 && (pos = findNodeSourcePosition(object)) != null) { - writeByte(POOL_NODE_SOURCE_POSITION); - ResolvedJavaMethod method = findNodeSourcePositionMethod(pos); - writePoolObject(method); - final int bci = findNodeSourcePositionBCI(pos); - writeInt(bci); - StackTraceElement ste = findMethodStackTraceElement(method, bci, pos); - if (ste != null && ste.getFileName() != null) { - writePoolObject(ste.getFileName()); - writeInt(ste.getLineNumber()); - } else { - writePoolObject(null); - } - writePoolObject(findNodeSourcePositionCaller(pos)); - } else { - Node node = findNode(object); - if (node != null) { - if (versionMajor >= 5) { - writeByte(POOL_NODE); - writeInt(findNodeId(node)); - writePoolObject(classForNode(node)); - return; - } - if (versionMajor == 4) { - object = classForNode(node); + case POOL_SIGNATURE: { + Signature signature = (Signature) found[0]; + int args = findSignatureParameterCount(signature); + writeShort((char) args); + for (int i = 0; i < args; i++) { + writePoolObject(findSignatureParameterTypeName(signature, i)); } + writePoolObject(findSignatureReturnTypeName(signature)); + break; } - NodeClass nodeClass = findNodeClass(object); - if (nodeClass != null) { - writeByte(POOL_NODE_CLASS); + case POOL_NODE_SOURCE_POSITION: { + NodeSourcePosition pos = (NodeSourcePosition) found[0]; + Objects.nonNull(pos); + ResolvedJavaMethod method = findNodeSourcePositionMethod(pos); + writePoolObject(method); + final int bci = findNodeSourcePositionBCI(pos); + writeInt(bci); + Iterator ste = findLocation(method, bci, pos).iterator(); + if (versionMajor >= 6) { + while (ste.hasNext()) { + Location loc = ste.next(); + URI uri; + try { + uri = findLocationURI(loc); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + if (uri == null) { + throw new IOException("No URI for " + loc); + } + String l = findLocationLanguage(loc); + if (l == null) { + continue; + } + writePoolObject(uri.toString()); + writeString(l); + writeInt(findLocationLine(loc)); + writeInt(findLocationStart(loc)); + writeInt(findLocationEnd(loc)); + } + writePoolObject(null); + } else { + Location first = ste.hasNext() ? ste.next() : null; + String fileName = first != null ? findLocationFile(first) : null; + if (fileName != null) { + writePoolObject(fileName); + writeInt(findLocationLine(first)); + } else { + writePoolObject(null); + } + } + writePoolObject(findNodeSourcePositionCaller(pos)); + break; + } + case POOL_NODE: { + Node node = (Node) found[0]; + Objects.nonNull(node); + writeInt(findNodeId(node)); + writePoolObject(classForNode(node)); + break; + } + case POOL_NODE_CLASS: { + NodeClass nodeClass = (NodeClass) found[0]; final Object clazz = findJavaClass(nodeClass); if (versionMajor >= 3) { writePoolObject(clazz); @@ -585,39 +652,50 @@ abstract class GraphProtocol= 0) { - writeByte(POOL_ENUM); - writePoolObject(findEnumClass(object)); - writeInt(enumOrdinal); } else { - writeByte(POOL_STRING); - writeString(object.toString()); + writeByte(KLASS); } - return; + break; } - writeByte(POOL_METHOD); - writePoolObject(findMethodDeclaringClass(method)); - writePoolObject(findMethodName(method)); - writePoolObject(findMethodSignature(method)); - writeInt(findMethodModifiers(method)); - writeBytes(findMethodCode(method)); + case POOL_METHOD: { + ResolvedJavaMethod method = (ResolvedJavaMethod) found[0]; + Objects.nonNull(method); + writePoolObject(findMethodDeclaringClass(method)); + writePoolObject(findMethodName(method)); + final Signature methodSignature = findMethodSignature(method); + if (findSignature(methodSignature) == null) { + throw new IOException("Should be recognized as signature: " + methodSignature + " for " + method); + } + writePoolObject(methodSignature); + writeInt(findMethodModifiers(method)); + writeBytes(findMethodCode(method)); + break; + } + case POOL_ENUM: { + int enumOrdinal = (int) found[0]; + writePoolObject(findEnumClass(object)); + writeInt(enumOrdinal); + break; + } + case POOL_STRING: { + writeString(object.toString()); + break; + } + default: + throw new IllegalStateException(); } } @@ -696,6 +774,16 @@ abstract class GraphProtocol { private final LinkedList availableIds; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java index 2bb39b3c0cd..9e12b09318b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java @@ -22,34 +22,43 @@ */ package org.graalvm.graphio; +import java.io.File; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.channels.WritableByteChannel; import java.util.Collection; import java.util.Map; -final class ProtocolImpl - extends GraphProtocol { +final class ProtocolImpl + extends GraphProtocol { private final GraphStructure structure; private final GraphTypes types; private final GraphBlocks blocks; private final GraphElements elements; + private final GraphLocations locations; ProtocolImpl(int major, int minor, GraphStructure structure, GraphTypes enums, GraphBlocks blocks, - GraphElements elements, WritableByteChannel channel) throws IOException { + GraphElements elements, + GraphLocations locs, + WritableByteChannel channel) throws IOException { super(channel, major, minor); this.structure = structure; this.types = enums; this.blocks = blocks; this.elements = elements; + this.locations = locs; } - ProtocolImpl(GraphProtocol parent, GraphStructure structure, GraphTypes enums, GraphBlocks blocks, - GraphElements elements) { + ProtocolImpl(GraphProtocol parent, GraphStructure structure, GraphTypes enums, GraphBlocks blocks, + GraphElements elements, + GraphLocations locs) { super(parent); this.structure = structure; this.types = enums; this.blocks = blocks; this.elements = elements; + this.locations = locs; } @Override @@ -285,8 +294,56 @@ final class ProtocolImpl findLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { + return locations.methodLocation(method, bci, pos); + } + + @Override + protected String findLocationFile(Location loc) throws IOException { + if (loc == null) { + return null; + } + URI u; + try { + u = locations.locationURI(loc); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + if (u == null) { + return null; + } + if (u.getScheme() == null) { + return u.getPath(); + } + if ("file".equals(u.getScheme())) { + return new File(u).getPath(); + } + return null; + } + + @Override + protected int findLocationLine(Location loc) { + return locations.locationLineNumber(loc); + } + + @Override + protected URI findLocationURI(Location loc) throws URISyntaxException { + return locations.locationURI(loc); + } + + @Override + protected String findLocationLanguage(Location loc) { + return locations.locationLanguage(loc); + } + + @Override + protected int findLocationStart(Location loc) { + return locations.locationOffsetStart(loc); + } + + @Override + protected int findLocationEnd(Location loc) { + return locations.locationOffsetEnd(loc); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java index f5055201351..9ebfb32cda2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java @@ -24,8 +24,8 @@ package org.graalvm.util.test; import static org.junit.Assert.assertEquals; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.test.GraalTest; import org.graalvm.util.ObjectSizeEstimate; import org.junit.Assume; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java index b28fc86fcac..b15544c7732 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java @@ -26,8 +26,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.Equivalence; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; /** * Calculates approximate estimates of the size of an object graph. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml deleted file mode 100644 index e07ad68fbed..00000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From ffd8e19eafd8298e17c8ae9f38cfd0abe509b81f Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 24 Apr 2018 10:26:54 -0700 Subject: [PATCH 029/102] 8202075: Crash when running compiler/codecache/OverflowCodeCacheTest.java Add missing null check in WhiteBox::allocate_code_blob() Reviewed-by: thartmann --- src/hotspot/share/prims/whitebox.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 44913f41868..6ff8b83e338 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1359,7 +1359,9 @@ CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) { { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type); - ::new (blob) BufferBlob("WB::DummyBlob", full_size); + if (blob != NULL) { + ::new (blob) BufferBlob("WB::DummyBlob", full_size); + } } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); From 15a89eeee4dc32269a7bcbdb727be4c3bad0b412 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 10 Apr 2018 17:07:21 +0200 Subject: [PATCH 030/102] 8201368: IfNode::fold_compares() may lead to incorrect execution Reviewed-by: neliasso, kvn --- src/hotspot/share/opto/cfgnode.hpp | 1 + src/hotspot/share/opto/ifnode.cpp | 64 +++++++++------ .../uncommontrap/FoldedIfNonDomMidIf.java | 79 +++++++++++++++++++ 3 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/uncommontrap/FoldedIfNonDomMidIf.java diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 4866e43eb47..a766115a68b 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -298,6 +298,7 @@ private: void reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn); ProjNode* uncommon_trap_proj(CallStaticJavaNode*& call) const; bool fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + static bool is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* unc); protected: ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 77af1c34c00..943eca9b805 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -775,6 +775,38 @@ bool IfNode::has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fa return success != NULL && fail != NULL; } +bool IfNode::is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* unc) { + // Different methods and methods containing jsrs are not supported. + ciMethod* method = unc->jvms()->method(); + ciMethod* dom_method = dom_unc->jvms()->method(); + if (method != dom_method || method->has_jsrs()) { + return false; + } + // Check that both traps are in the same activation of the method (instead + // of two activations being inlined through different call sites) by verifying + // that the call stacks are equal for both JVMStates. + JVMState* dom_caller = dom_unc->jvms()->caller(); + JVMState* caller = unc->jvms()->caller(); + if ((dom_caller == NULL) != (caller == NULL)) { + // The current method must either be inlined into both dom_caller and + // caller or must not be inlined at all (top method). Bail out otherwise. + return false; + } else if (dom_caller != NULL && !dom_caller->same_calls_as(caller)) { + return false; + } + // Check that the bci of the dominating uncommon trap dominates the bci + // of the dominated uncommon trap. Otherwise we may not re-execute + // the dominated check after deoptimization from the merged uncommon trap. + ciTypeFlow* flow = dom_method->get_flow_analysis(); + int bci = unc->jvms()->bci(); + int dom_bci = dom_unc->jvms()->bci(); + if (!flow->is_dominated_by(bci, dom_bci)) { + return false; + } + + return true; +} + // Return projection that leads to an uncommon trap if any ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { for (int i = 0; i < 2; i++) { @@ -811,31 +843,7 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod return false; } - // Different methods and methods containing jsrs are not supported. - ciMethod* method = unc->jvms()->method(); - ciMethod* dom_method = dom_unc->jvms()->method(); - if (method != dom_method || method->has_jsrs()) { - return false; - } - // Check that both traps are in the same activation of the method (instead - // of two activations being inlined through different call sites) by verifying - // that the call stacks are equal for both JVMStates. - JVMState* dom_caller = dom_unc->jvms()->caller(); - JVMState* caller = unc->jvms()->caller(); - if ((dom_caller == NULL) != (caller == NULL)) { - // The current method must either be inlined into both dom_caller and - // caller or must not be inlined at all (top method). Bail out otherwise. - return false; - } else if (dom_caller != NULL && !dom_caller->same_calls_as(caller)) { - return false; - } - // Check that the bci of the dominating uncommon trap dominates the bci - // of the dominated uncommon trap. Otherwise we may not re-execute - // the dominated check after deoptimization from the merged uncommon trap. - ciTypeFlow* flow = dom_method->get_flow_analysis(); - int bci = unc->jvms()->bci(); - int dom_bci = dom_unc->jvms()->bci(); - if (!flow->is_dominated_by(bci, dom_bci)) { + if (!is_dominator_unc(dom_unc, unc)) { return false; } @@ -843,6 +851,8 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod // will be changed and the state of the dominating If will be // used. Checked that we didn't apply this transformation in a // previous compilation and it didn't cause too many traps + ciMethod* dom_method = dom_unc->jvms()->method(); + int dom_bci = dom_unc->jvms()->bci(); if (!igvn->C->too_many_traps(dom_method, dom_bci, Deoptimization::Reason_unstable_fused_if) && !igvn->C->too_many_traps(dom_method, dom_bci, Deoptimization::Reason_range_check)) { success = unc_proj; @@ -1220,6 +1230,10 @@ bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { return false; } + if (!is_dominator_unc(dom_unc, unc)) { + return false; + } + return true; } } diff --git a/test/hotspot/jtreg/compiler/uncommontrap/FoldedIfNonDomMidIf.java b/test/hotspot/jtreg/compiler/uncommontrap/FoldedIfNonDomMidIf.java new file mode 100644 index 00000000000..1e1e55b1811 --- /dev/null +++ b/test/hotspot/jtreg/compiler/uncommontrap/FoldedIfNonDomMidIf.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 8201368 + * @summary IfNode::fold_compares() may lead to incorrect execution + * + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation FoldedIfNonDomMidIf + * + */ + +public class FoldedIfNonDomMidIf { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test_helper(0, 0); + test_helper(20, 0); + test(12); + } + if (test(14) != null) { + throw new RuntimeException("Incorrect code execution"); + } + } + + private static Object test(int i) { + return test_helper(i, 0x42); + } + + static class A { + + } + + static final MyException myex = new MyException(); + + private static Object test_helper(int i, int j) { + Object res = null; + try { + if (i < 10) { + throw myex; + } + + if (i == 14) { + + } + + if (i > 15) { + throw myex; + } + } catch (MyException e) { + if (j == 0x42) { + res = new A(); + } + } + return res; + } + + private static class MyException extends Exception { + } +} From c6ece0ba39eb4111b09ed6780ce660c9aaf0a7f3 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Tue, 24 Apr 2018 12:20:10 -0700 Subject: [PATCH 031/102] 8202157: remove the use of string keys at InapplicableMethodException Reviewed-by: mcimadamore --- .../com/sun/tools/javac/comp/Infer.java | 21 ++---------- .../com/sun/tools/javac/comp/Resolve.java | 33 ++++--------------- 2 files changed, 10 insertions(+), 44 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java index 437fac7f9d4..e2cfde41ed3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -138,23 +138,8 @@ public class Infer { List messages = List.nil(); - InferenceException(JCDiagnostic.Factory diags) { - super(diags); - } - - @Override - InapplicableMethodException setMessage() { - throw new AssertionError("InferenceException is immutable"); - } - - @Override - InapplicableMethodException setMessage(JCDiagnostic diag) { - throw new AssertionError("InferenceException is immutable"); - } - - @Override - InapplicableMethodException setMessage(String key, Object... args) { - throw new AssertionError("InferenceException is immutable"); + InferenceException() { + super(null); } @Override @@ -164,7 +149,7 @@ public class Infer { } InferenceException error(JCDiagnostic diag) { - InferenceException result = new InferenceException(diags); + InferenceException result = new InferenceException(); if (diag != null) { result.messages = result.messages.append(diag); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 5486953fd0d..d687acf56a1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -143,9 +143,6 @@ public class Resolve { checkVarargsAccessAfterResolution = Feature.POST_APPLICABILITY_VARARGS_ACCESS_CHECK.allowedInSource(source); polymorphicSignatureScope = WriteableScope.create(syms.noSymbol); - - inapplicableMethodException = new InapplicableMethodException(diags); - allowModules = Feature.MODULES.allowedInSource(source); } @@ -575,7 +572,7 @@ public class Resolve { ForAll pmt = (ForAll) mt; if (typeargtypes.length() != pmt.tvars.length()) // not enough args - throw inapplicableMethodException.setMessage("wrong.number.type.args", Integer.toString(pmt.tvars.length())); + throw new InapplicableMethodException(diags.fragment(Fragments.WrongNumberTypeArgs(Integer.toString(pmt.tvars.length())))); // Check type arguments are within bounds List formals = pmt.tvars; List actuals = typeargtypes; @@ -583,8 +580,9 @@ public class Resolve { List bounds = types.subst(types.getBounds((TypeVar)formals.head), pmt.tvars, typeargtypes); for (; bounds.nonEmpty(); bounds = bounds.tail) { - if (!types.isSubtypeUnchecked(actuals.head, bounds.head, warn)) - throw inapplicableMethodException.setMessage("explicit.param.do.not.conform.to.bounds",actuals.head, bounds); + if (!types.isSubtypeUnchecked(actuals.head, bounds.head, warn)) { + throw new InapplicableMethodException(diags.fragment(Fragments.ExplicitParamDoNotConformToBounds(actuals.head, bounds))); + } } formals = formals.tail; actuals = actuals.tail; @@ -820,8 +818,7 @@ public class Resolve { String key = inferDiag ? diag.inferKey : diag.basicKey; throw inferDiag ? infer.error(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)) : - inapplicableMethodException - .setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)); + new InapplicableMethodException(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)); } public MethodCheck mostSpecificCheck(List actuals) { @@ -1007,7 +1004,7 @@ public class Resolve { } public void report(DiagnosticPosition pos, JCDiagnostic details) { - throw inapplicableMethodException.setMessage(details); + throw new InapplicableMethodException(details); } public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { @@ -1368,31 +1365,15 @@ public class Resolve { private static final long serialVersionUID = 0; JCDiagnostic diagnostic; - JCDiagnostic.Factory diags; - InapplicableMethodException(JCDiagnostic.Factory diags) { - this.diagnostic = null; - this.diags = diags; - } - InapplicableMethodException setMessage() { - return setMessage((JCDiagnostic)null); - } - InapplicableMethodException setMessage(String key) { - return setMessage(key != null ? diags.fragment(key) : null); - } - InapplicableMethodException setMessage(String key, Object... args) { - return setMessage(key != null ? diags.fragment(key, args) : null); - } - InapplicableMethodException setMessage(JCDiagnostic diag) { + InapplicableMethodException(JCDiagnostic diag) { this.diagnostic = diag; - return this; } public JCDiagnostic getDiagnostic() { return diagnostic; } } - private final InapplicableMethodException inapplicableMethodException; /* *************************************************************************** * Symbol lookup From 93691571bcb643be83dc88a8434dae3e2b45dbad Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 24 Apr 2018 15:07:20 -0700 Subject: [PATCH 032/102] 8200303: C2 should leverage profiling for lookupswitch/tableswitch Reviewed-by: kvn, thartmann --- src/hotspot/share/adlc/formssel.cpp | 3 + src/hotspot/share/adlc/output_c.cpp | 3 + src/hotspot/share/c1/c1_GraphBuilder.cpp | 4 +- src/hotspot/share/c1/c1_LIRGenerator.cpp | 61 +++ src/hotspot/share/opto/cfgnode.hpp | 7 +- src/hotspot/share/opto/gcm.cpp | 3 +- src/hotspot/share/opto/machnode.hpp | 10 + src/hotspot/share/opto/node.hpp | 3 + src/hotspot/share/opto/parse.hpp | 9 +- src/hotspot/share/opto/parse2.cpp | 627 +++++++++++++++++++---- src/hotspot/share/runtime/globals.hpp | 2 + src/hotspot/share/runtime/vmStructs.cpp | 3 + 12 files changed, 629 insertions(+), 106 deletions(-) diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 25c1c023a57..60f8c18b39f 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1171,6 +1171,9 @@ const char *InstructForm::mach_base_class(FormDict &globals) const { else if (is_ideal_nop()) { return "MachNopNode"; } + else if (is_ideal_jump()) { + return "MachJumpNode"; + } else if (is_mach_constant()) { return "MachConstantNode"; } diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 302e67bf5fb..d8906ed0bc3 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -3936,6 +3936,9 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden fprintf(fp_cpp, "%s node->_prob = _leaf->as_If()->_prob;\n", indent); fprintf(fp_cpp, "%s node->_fcnt = _leaf->as_If()->_fcnt;\n", indent); } + if (inst->is_ideal_jump()) { + fprintf(fp_cpp, "%s node->_probs = _leaf->as_Jump()->_probs;\n", indent); + } if( inst->is_ideal_fastlock() ) { fprintf(fp_cpp, "%s node->_counters = _leaf->as_FastLock()->counters();\n", indent); fprintf(fp_cpp, "%s node->_rtm_counters = _leaf->as_FastLock()->rtm_counters();\n", indent); diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 264c886eb30..ca9fc3edd15 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1324,7 +1324,7 @@ void GraphBuilder::ret(int local_index) { void GraphBuilder::table_switch() { Bytecode_tableswitch sw(stream()); const int l = sw.length(); - if (CanonicalizeNodes && l == 1) { + if (CanonicalizeNodes && l == 1 && compilation()->env()->comp_level() != CompLevel_full_profile) { // total of 2 successors => use If instead of switch // Note: This code should go into the canonicalizer as soon as it can // can handle canonicalized forms that contain more than one node. @@ -1368,7 +1368,7 @@ void GraphBuilder::table_switch() { void GraphBuilder::lookup_switch() { Bytecode_lookupswitch sw(stream()); const int l = sw.number_of_pairs(); - if (CanonicalizeNodes && l == 1) { + if (CanonicalizeNodes && l == 1 && compilation()->env()->comp_level() != CompLevel_full_profile) { // total of 2 successors => use If instead of switch // Note: This code should go into the canonicalizer as soon as it can // can handle canonicalized forms that contain more than one node. diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 61105c1986b..32b5ce86cac 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -2552,6 +2552,36 @@ void LIRGenerator::do_TableSwitch(TableSwitch* x) { int hi_key = x->hi_key(); int len = x->length(); LIR_Opr value = tag.result(); + + if (compilation()->env()->comp_level() == CompLevel_full_profile && UseSwitchProfiling) { + ciMethod* method = x->state()->scope()->method(); + ciMethodData* md = method->method_data_or_null(); + ciProfileData* data = md->bci_to_data(x->state()->bci()); + assert(data->is_MultiBranchData(), "bad profile data?"); + int default_count_offset = md->byte_offset_of_slot(data, MultiBranchData::default_count_offset()); + LIR_Opr md_reg = new_register(T_METADATA); + __ metadata2reg(md->constant_encoding(), md_reg); + LIR_Opr data_offset_reg = new_pointer_register(); + LIR_Opr tmp_reg = new_pointer_register(); + + __ move(LIR_OprFact::intptrConst(default_count_offset), data_offset_reg); + for (int i = 0; i < len; i++) { + int count_offset = md->byte_offset_of_slot(data, MultiBranchData::case_count_offset(i)); + __ cmp(lir_cond_equal, value, i + lo_key); + __ move(data_offset_reg, tmp_reg); + __ cmove(lir_cond_equal, + LIR_OprFact::intptrConst(count_offset), + tmp_reg, + data_offset_reg, T_INT); + } + + LIR_Opr data_reg = new_pointer_register(); + LIR_Address* data_addr = new LIR_Address(md_reg, data_offset_reg, data_reg->type()); + __ move(data_addr, data_reg); + __ add(data_reg, LIR_OprFact::intptrConst(1), data_reg); + __ move(data_reg, data_addr); + } + if (UseTableRanges) { do_SwitchRanges(create_lookup_ranges(x), value, x->default_sux()); } else { @@ -2577,6 +2607,37 @@ void LIRGenerator::do_LookupSwitch(LookupSwitch* x) { move_to_phi(x->state()); LIR_Opr value = tag.result(); + int len = x->length(); + + if (compilation()->env()->comp_level() == CompLevel_full_profile && UseSwitchProfiling) { + ciMethod* method = x->state()->scope()->method(); + ciMethodData* md = method->method_data_or_null(); + ciProfileData* data = md->bci_to_data(x->state()->bci()); + assert(data->is_MultiBranchData(), "bad profile data?"); + int default_count_offset = md->byte_offset_of_slot(data, MultiBranchData::default_count_offset()); + LIR_Opr md_reg = new_register(T_METADATA); + __ metadata2reg(md->constant_encoding(), md_reg); + LIR_Opr data_offset_reg = new_pointer_register(); + LIR_Opr tmp_reg = new_pointer_register(); + + __ move(LIR_OprFact::intptrConst(default_count_offset), data_offset_reg); + for (int i = 0; i < len; i++) { + int count_offset = md->byte_offset_of_slot(data, MultiBranchData::case_count_offset(i)); + __ cmp(lir_cond_equal, value, x->key_at(i)); + __ move(data_offset_reg, tmp_reg); + __ cmove(lir_cond_equal, + LIR_OprFact::intptrConst(count_offset), + tmp_reg, + data_offset_reg, T_INT); + } + + LIR_Opr data_reg = new_pointer_register(); + LIR_Address* data_addr = new LIR_Address(md_reg, data_offset_reg, data_reg->type()); + __ move(data_addr, data_reg); + __ add(data_reg, LIR_OprFact::intptrConst(1), data_reg); + __ move(data_reg, data_addr); + } + if (UseTableRanges) { do_SwitchRanges(create_lookup_ranges(x), value, x->default_sux()); } else { diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index a766115a68b..80b8fb29e64 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -485,8 +485,13 @@ public: // Indirect branch. Uses PCTable above to implement a switch statement. // It emits as a table load and local branch. class JumpNode : public PCTableNode { + virtual uint size_of() const { return sizeof(*this); } public: - JumpNode( Node* control, Node* switch_val, uint size) : PCTableNode(control, switch_val, size) { + float* _probs; // probability of each projection + float _fcnt; // total number of times this Jump was executed + JumpNode( Node* control, Node* switch_val, uint size, float* probs, float cnt) + : PCTableNode(control, switch_val, size), + _probs(probs), _fcnt(cnt) { init_class_id(Class_Jump); } virtual int Opcode() const; diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 50d98da8f21..ccadf39f192 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1867,8 +1867,7 @@ float Block::succ_prob(uint i) { } case Op_Jump: - // Divide the frequency between all successors evenly - return 1.0f/_num_succs; + return n->as_MachJump()->_probs[get_node(i + eidx + 1)->as_JumpProj()->_con]; case Op_Catch: { const CatchProjNode *ci = get_node(i + eidx + 1)->as_CatchProj(); diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 8bfd1e5b9c8..a14d68d17e3 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -750,6 +750,16 @@ public: #endif }; +//------------------------------MachJumpNode----------------------------------- +// Machine-specific versions of JumpNodes +class MachJumpNode : public MachConstantNode { +public: + float* _probs; + MachJumpNode() : MachConstantNode() { + init_class_id(Class_MachJump); + } +}; + //------------------------------MachGotoNode----------------------------------- // Machine-specific versions of GotoNodes class MachGotoNode : public MachBranchNode { diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index d2acf0ec669..82ca71b299c 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -94,6 +94,7 @@ class MachConstantBaseNode; class MachConstantNode; class MachGotoNode; class MachIfNode; +class MachJumpNode; class MachNode; class MachNullCheckNode; class MachProjNode; @@ -651,6 +652,7 @@ public: DEFINE_CLASS_ID(MachTemp, Mach, 3) DEFINE_CLASS_ID(MachConstantBase, Mach, 4) DEFINE_CLASS_ID(MachConstant, Mach, 5) + DEFINE_CLASS_ID(MachJump, MachConstant, 0) DEFINE_CLASS_ID(MachMerge, Mach, 6) DEFINE_CLASS_ID(Type, Node, 2) @@ -831,6 +833,7 @@ public: DEFINE_CLASS_QUERY(MachConstant) DEFINE_CLASS_QUERY(MachGoto) DEFINE_CLASS_QUERY(MachIf) + DEFINE_CLASS_QUERY(MachJump) DEFINE_CLASS_QUERY(MachNullCheck) DEFINE_CLASS_QUERY(MachProj) DEFINE_CLASS_QUERY(MachReturn) diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index c2b88595333..503fb67c977 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -552,17 +552,18 @@ class Parse : public GraphKit { void sharpen_type_after_if(BoolTest::mask btest, Node* con, const Type* tcon, Node* val, const Type* tval); - IfNode* jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask); + IfNode* jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask, float prob, float cnt); Node* jump_if_join(Node* iffalse, Node* iftrue); - void jump_if_true_fork(IfNode *ifNode, int dest_bci_if_true, int prof_table_index); - void jump_if_false_fork(IfNode *ifNode, int dest_bci_if_false, int prof_table_index); - void jump_if_always_fork(int dest_bci_if_true, int prof_table_index); + void jump_if_true_fork(IfNode *ifNode, int dest_bci_if_true, int prof_table_index, bool unc); + void jump_if_false_fork(IfNode *ifNode, int dest_bci_if_false, int prof_table_index, bool unc); + void jump_if_always_fork(int dest_bci_if_true, int prof_table_index, bool unc); friend class SwitchRange; void do_tableswitch(); void do_lookupswitch(); void jump_switch_ranges(Node* a, SwitchRange* lo, SwitchRange* hi, int depth = 0); bool create_jump_tables(Node* a, SwitchRange* lo, SwitchRange* hi); + void linear_search_switch_ranges(Node* key_val, SwitchRange*& lo, SwitchRange*& hi); void decrement_age(); // helper functions for methodData style profiling diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 5e8056f3d16..3c632a85b0c 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -186,10 +186,10 @@ Node* Parse::array_addressing(BasicType type, int vals, const Type* *result2) { // returns IfNode -IfNode* Parse::jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask) { - Node *cmp = _gvn.transform( new CmpINode( a, b)); // two cases: shiftcount > 32 and shiftcount <= 32 - Node *tst = _gvn.transform( new BoolNode( cmp, mask)); - IfNode *iff = create_and_map_if( control(), tst, ((mask == BoolTest::eq) ? PROB_STATIC_INFREQUENT : PROB_FAIR), COUNT_UNKNOWN ); +IfNode* Parse::jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask, float prob, float cnt) { + Node *cmp = _gvn.transform(new CmpINode(a, b)); // two cases: shiftcount > 32 and shiftcount <= 32 + Node *tst = _gvn.transform(new BoolNode(cmp, mask)); + IfNode *iff = create_and_map_if(control(), tst, prob, cnt); return iff; } @@ -205,15 +205,27 @@ Node* Parse::jump_if_join(Node* iffalse, Node* iftrue) { return region; } +// sentinel value for the target bci to mark never taken branches +// (according to profiling) +static const int never_reached = INT_MAX; //------------------------------helper for tableswitch------------------------- -void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, int prof_table_index) { +void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, int prof_table_index, bool unc) { // True branch, use existing map info { PreserveJVMState pjvms(this); Node *iftrue = _gvn.transform( new IfTrueNode (iff) ); set_control( iftrue ); - profile_switch_case(prof_table_index); - merge_new_path(dest_bci_if_true); + if (unc) { + repush_if_args(); + uncommon_trap(Deoptimization::Reason_unstable_if, + Deoptimization::Action_reinterpret, + NULL, + "taken always"); + } else { + assert(dest_bci_if_true != never_reached, "inconsistent dest"); + profile_switch_case(prof_table_index); + merge_new_path(dest_bci_if_true); + } } // False branch @@ -221,13 +233,22 @@ void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, int prof_table_ set_control( iffalse ); } -void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, int prof_table_index) { +void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, int prof_table_index, bool unc) { // True branch, use existing map info { PreserveJVMState pjvms(this); Node *iffalse = _gvn.transform( new IfFalseNode (iff) ); set_control( iffalse ); - profile_switch_case(prof_table_index); - merge_new_path(dest_bci_if_true); + if (unc) { + repush_if_args(); + uncommon_trap(Deoptimization::Reason_unstable_if, + Deoptimization::Action_reinterpret, + NULL, + "taken never"); + } else { + assert(dest_bci_if_true != never_reached, "inconsistent dest"); + profile_switch_case(prof_table_index); + merge_new_path(dest_bci_if_true); + } } // False branch @@ -235,10 +256,19 @@ void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, int prof_table set_control( iftrue ); } -void Parse::jump_if_always_fork(int dest_bci, int prof_table_index) { +void Parse::jump_if_always_fork(int dest_bci, int prof_table_index, bool unc) { // False branch, use existing map and control() - profile_switch_case(prof_table_index); - merge_new_path(dest_bci); + if (unc) { + repush_if_args(); + uncommon_trap(Deoptimization::Reason_unstable_if, + Deoptimization::Action_reinterpret, + NULL, + "taken never"); + } else { + assert(dest_bci != never_reached, "inconsistent dest"); + profile_switch_case(prof_table_index); + merge_new_path(dest_bci); + } } @@ -261,6 +291,7 @@ class SwitchRange : public StackObj { jint _hi; // inclusive upper limit int _dest; int _table_index; // index into method data table + float _cnt; // how many times this range was hit according to profiling public: jint lo() const { return _lo; } @@ -268,44 +299,111 @@ public: int dest() const { return _dest; } int table_index() const { return _table_index; } bool is_singleton() const { return _lo == _hi; } + float cnt() const { return _cnt; } - void setRange(jint lo, jint hi, int dest, int table_index) { + void setRange(jint lo, jint hi, int dest, int table_index, float cnt) { assert(lo <= hi, "must be a non-empty range"); - _lo = lo, _hi = hi; _dest = dest; _table_index = table_index; + _lo = lo, _hi = hi; _dest = dest; _table_index = table_index; _cnt = cnt; + assert(_cnt >= 0, ""); } - bool adjoinRange(jint lo, jint hi, int dest, int table_index) { + bool adjoinRange(jint lo, jint hi, int dest, int table_index, float cnt, bool trim_ranges) { assert(lo <= hi, "must be a non-empty range"); - if (lo == _hi+1 && dest == _dest && table_index == _table_index) { + if (lo == _hi+1 && table_index == _table_index) { + // see merge_ranges() comment below + if (trim_ranges) { + if (cnt == 0) { + if (_cnt != 0) { + return false; + } + if (dest != _dest) { + _dest = never_reached; + } + } else { + if (_cnt == 0) { + return false; + } + if (dest != _dest) { + return false; + } + } + } else { + if (dest != _dest) { + return false; + } + } _hi = hi; + _cnt += cnt; return true; } return false; } - void set (jint value, int dest, int table_index) { - setRange(value, value, dest, table_index); + void set (jint value, int dest, int table_index, float cnt) { + setRange(value, value, dest, table_index, cnt); } - bool adjoin(jint value, int dest, int table_index) { - return adjoinRange(value, value, dest, table_index); + bool adjoin(jint value, int dest, int table_index, float cnt, bool trim_ranges) { + return adjoinRange(value, value, dest, table_index, cnt, trim_ranges); + } + bool adjoin(SwitchRange& other) { + return adjoinRange(other._lo, other._hi, other._dest, other._table_index, other._cnt, false); } void print() { if (is_singleton()) - tty->print(" {%d}=>%d", lo(), dest()); + tty->print(" {%d}=>%d (cnt=%f)", lo(), dest(), cnt()); else if (lo() == min_jint) - tty->print(" {..%d}=>%d", hi(), dest()); + tty->print(" {..%d}=>%d (cnt=%f)", hi(), dest(), cnt()); else if (hi() == max_jint) - tty->print(" {%d..}=>%d", lo(), dest()); + tty->print(" {%d..}=>%d (cnt=%f)", lo(), dest(), cnt()); else - tty->print(" {%d..%d}=>%d", lo(), hi(), dest()); + tty->print(" {%d..%d}=>%d (cnt=%f)", lo(), hi(), dest(), cnt()); } }; +// We try to minimize the number of ranges and the size of the taken +// ones using profiling data. When ranges are created, +// SwitchRange::adjoinRange() only allows 2 adjoining ranges to merge +// if both were never hit or both were hit to build longer unreached +// ranges. Here, we now merge adjoining ranges with the same +// destination and finally set destination of unreached ranges to the +// special value never_reached because it can help minimize the number +// of tests that are necessary. +// +// For instance: +// [0, 1] to target1 sometimes taken +// [1, 2] to target1 never taken +// [2, 3] to target2 never taken +// would lead to: +// [0, 1] to target1 sometimes taken +// [1, 3] never taken +// +// (first 2 ranges to target1 are not merged) +static void merge_ranges(SwitchRange* ranges, int& rp) { + if (rp == 0) { + return; + } + int shift = 0; + for (int j = 0; j < rp; j++) { + SwitchRange& r1 = ranges[j-shift]; + SwitchRange& r2 = ranges[j+1]; + if (r1.adjoin(r2)) { + shift++; + } else if (shift > 0) { + ranges[j+1-shift] = r2; + } + } + rp -= shift; + for (int j = 0; j <= rp; j++) { + SwitchRange& r = ranges[j]; + if (r.cnt() == 0 && r.dest() != never_reached) { + r.setRange(r.lo(), r.hi(), never_reached, r.table_index(), r.cnt()); + } + } +} //-------------------------------do_tableswitch-------------------------------- void Parse::do_tableswitch() { Node* lookup = pop(); - // Get information about tableswitch int default_dest = iter().get_dest_table(0); int lo_index = iter().get_int_table(1); @@ -319,31 +417,58 @@ void Parse::do_tableswitch() { return; } + ciMethodData* methodData = method()->method_data(); + ciMultiBranchData* profile = NULL; + if (methodData->is_mature() && UseSwitchProfiling) { + ciProfileData* data = methodData->bci_to_data(bci()); + if (data != NULL && data->is_MultiBranchData()) { + profile = (ciMultiBranchData*)data; + } + } + bool trim_ranges = !method_data_update() && !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); + // generate decision tree, using trichotomy when possible int rnum = len+2; bool makes_backward_branch = false; SwitchRange* ranges = NEW_RESOURCE_ARRAY(SwitchRange, rnum); int rp = -1; if (lo_index != min_jint) { - ranges[++rp].setRange(min_jint, lo_index-1, default_dest, NullTableIndex); + uint cnt = 1; + if (profile != NULL) { + cnt = profile->default_count() / (hi_index != max_jint ? 2 : 1); + } + ranges[++rp].setRange(min_jint, lo_index-1, default_dest, NullTableIndex, cnt); } for (int j = 0; j < len; j++) { jint match_int = lo_index+j; int dest = iter().get_dest_table(j+3); makes_backward_branch |= (dest <= bci()); int table_index = method_data_update() ? j : NullTableIndex; - if (rp < 0 || !ranges[rp].adjoin(match_int, dest, table_index)) { - ranges[++rp].set(match_int, dest, table_index); + uint cnt = 1; + if (profile != NULL) { + cnt = profile->count_at(j); + } + if (rp < 0 || !ranges[rp].adjoin(match_int, dest, table_index, cnt, trim_ranges)) { + ranges[++rp].set(match_int, dest, table_index, cnt); } } jint highest = lo_index+(len-1); assert(ranges[rp].hi() == highest, ""); - if (highest != max_jint - && !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, NullTableIndex)) { - ranges[++rp].setRange(highest+1, max_jint, default_dest, NullTableIndex); + if (highest != max_jint) { + uint cnt = 1; + if (profile != NULL) { + cnt = profile->default_count() / (lo_index != min_jint ? 2 : 1); + } + if (!ranges[rp].adjoinRange(highest+1, max_jint, default_dest, NullTableIndex, cnt, trim_ranges)) { + ranges[++rp].setRange(highest+1, max_jint, default_dest, NullTableIndex, cnt); + } } assert(rp < len+2, "not too many ranges"); + if (trim_ranges) { + merge_ranges(ranges, rp); + } + // Safepoint in case if backward branch observed if( makes_backward_branch && UseLoopSafepoints ) add_safepoint(); @@ -365,48 +490,263 @@ void Parse::do_lookupswitch() { return; } - // generate decision tree, using trichotomy when possible - jint* table = NEW_RESOURCE_ARRAY(jint, len*2); - { - for( int j = 0; j < len; j++ ) { - table[j+j+0] = iter().get_int_table(2+j+j); - table[j+j+1] = iter().get_dest_table(2+j+j+1); + ciMethodData* methodData = method()->method_data(); + ciMultiBranchData* profile = NULL; + if (methodData->is_mature() && UseSwitchProfiling) { + ciProfileData* data = methodData->bci_to_data(bci()); + if (data != NULL && data->is_MultiBranchData()) { + profile = (ciMultiBranchData*)data; } - qsort( table, len, 2*sizeof(table[0]), jint_cmp ); + } + bool trim_ranges = !method_data_update() && !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); + + // generate decision tree, using trichotomy when possible + jint* table = NEW_RESOURCE_ARRAY(jint, len*3); + { + for (int j = 0; j < len; j++) { + table[3*j+0] = iter().get_int_table(2+2*j); + table[3*j+1] = iter().get_dest_table(2+2*j+1); + table[3*j+2] = profile == NULL ? 1 : profile->count_at(j); + } + qsort(table, len, 3*sizeof(table[0]), jint_cmp); + } + + float defaults = 0; + jint prev = min_jint; + for (int j = 0; j < len; j++) { + jint match_int = table[3*j+0]; + if (match_int != prev) { + defaults += (float)match_int - prev; + } + prev = match_int+1; + } + if (prev-1 != max_jint) { + defaults += (float)max_jint - prev + 1; + } + float default_cnt = 1; + if (profile != NULL) { + default_cnt = profile->default_count()/defaults; } int rnum = len*2+1; bool makes_backward_branch = false; SwitchRange* ranges = NEW_RESOURCE_ARRAY(SwitchRange, rnum); int rp = -1; - for( int j = 0; j < len; j++ ) { - jint match_int = table[j+j+0]; - int dest = table[j+j+1]; + for (int j = 0; j < len; j++) { + jint match_int = table[3*j+0]; + int dest = table[3*j+1]; + int cnt = table[3*j+2]; int next_lo = rp < 0 ? min_jint : ranges[rp].hi()+1; int table_index = method_data_update() ? j : NullTableIndex; makes_backward_branch |= (dest <= bci()); - if( match_int != next_lo ) { - ranges[++rp].setRange(next_lo, match_int-1, default_dest, NullTableIndex); + float c = default_cnt * ((float)match_int - next_lo); + if (match_int != next_lo && (rp < 0 || !ranges[rp].adjoinRange(next_lo, match_int-1, default_dest, NullTableIndex, c, trim_ranges))) { + assert(default_dest != never_reached, "sentinel value for dead destinations"); + ranges[++rp].setRange(next_lo, match_int-1, default_dest, NullTableIndex, c); } - if( rp < 0 || !ranges[rp].adjoin(match_int, dest, table_index) ) { - ranges[++rp].set(match_int, dest, table_index); + if (rp < 0 || !ranges[rp].adjoin(match_int, dest, table_index, cnt, trim_ranges)) { + assert(dest != never_reached, "sentinel value for dead destinations"); + ranges[++rp].set(match_int, dest, table_index, cnt); } } - jint highest = table[2*(len-1)]; + jint highest = table[3*(len-1)]; assert(ranges[rp].hi() == highest, ""); - if( highest != max_jint - && !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, NullTableIndex) ) { - ranges[++rp].setRange(highest+1, max_jint, default_dest, NullTableIndex); + if (highest != max_jint && + !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, NullTableIndex, default_cnt * ((float)max_jint - highest), trim_ranges)) { + ranges[++rp].setRange(highest+1, max_jint, default_dest, NullTableIndex, default_cnt * ((float)max_jint - highest)); } assert(rp < rnum, "not too many ranges"); + if (trim_ranges) { + merge_ranges(ranges, rp); + } + // Safepoint in case backward branch observed - if( makes_backward_branch && UseLoopSafepoints ) + if (makes_backward_branch && UseLoopSafepoints) add_safepoint(); jump_switch_ranges(lookup, &ranges[0], &ranges[rp]); } +static float if_prob(float taken_cnt, float total_cnt) { + assert(taken_cnt <= total_cnt, ""); + if (total_cnt == 0) { + return PROB_FAIR; + } + float p = taken_cnt / total_cnt; + return MIN2(MAX2(p, PROB_MIN), PROB_MAX); +} + +static float if_cnt(float cnt) { + if (cnt == 0) { + return COUNT_UNKNOWN; + } + return cnt; +} + +static float sum_of_cnts(SwitchRange *lo, SwitchRange *hi) { + float total_cnt = 0; + for (SwitchRange* sr = lo; sr <= hi; sr++) { + total_cnt += sr->cnt(); + } + return total_cnt; +} + +class SwitchRanges : public ResourceObj { +public: + SwitchRange* _lo; + SwitchRange* _hi; + SwitchRange* _mid; + float _cost; + + enum { + Start, + LeftDone, + RightDone, + Done + } _state; + + SwitchRanges(SwitchRange *lo, SwitchRange *hi) + : _lo(lo), _hi(hi), _mid(NULL), + _cost(0), _state(Start) { + } + + SwitchRanges() + : _lo(NULL), _hi(NULL), _mid(NULL), + _cost(0), _state(Start) {} +}; + +// Estimate cost of performing a binary search on lo..hi +static float compute_tree_cost(SwitchRange *lo, SwitchRange *hi, float total_cnt) { + GrowableArray tree; + SwitchRanges root(lo, hi); + tree.push(root); + + float cost = 0; + do { + SwitchRanges& r = *tree.adr_at(tree.length()-1); + if (r._hi != r._lo) { + if (r._mid == NULL) { + float r_cnt = sum_of_cnts(r._lo, r._hi); + + if (r_cnt == 0) { + tree.pop(); + cost = 0; + continue; + } + + SwitchRange* mid = NULL; + mid = r._lo; + for (float cnt = 0; ; ) { + assert(mid <= r._hi, "out of bounds"); + cnt += mid->cnt(); + if (cnt > r_cnt / 2) { + break; + } + mid++; + } + assert(mid <= r._hi, "out of bounds"); + r._mid = mid; + r._cost = r_cnt / total_cnt; + } + r._cost += cost; + if (r._state < SwitchRanges::LeftDone && r._mid > r._lo) { + cost = 0; + r._state = SwitchRanges::LeftDone; + tree.push(SwitchRanges(r._lo, r._mid-1)); + } else if (r._state < SwitchRanges::RightDone) { + cost = 0; + r._state = SwitchRanges::RightDone; + tree.push(SwitchRanges(r._mid == r._lo ? r._mid+1 : r._mid, r._hi)); + } else { + tree.pop(); + cost = r._cost; + } + } else { + tree.pop(); + cost = r._cost; + } + } while (tree.length() > 0); + + + return cost; +} + +// It sometimes pays off to test most common ranges before the binary search +void Parse::linear_search_switch_ranges(Node* key_val, SwitchRange*& lo, SwitchRange*& hi) { + uint nr = hi - lo + 1; + float total_cnt = sum_of_cnts(lo, hi); + + float min = compute_tree_cost(lo, hi, total_cnt); + float extra = 1; + float sub = 0; + + SwitchRange* array1 = lo; + SwitchRange* array2 = NEW_RESOURCE_ARRAY(SwitchRange, nr); + + SwitchRange* ranges = NULL; + + while (nr >= 2) { + assert(lo == array1 || lo == array2, "one the 2 already allocated arrays"); + ranges = (lo == array1) ? array2 : array1; + + // Find highest frequency range + SwitchRange* candidate = lo; + for (SwitchRange* sr = lo+1; sr <= hi; sr++) { + if (sr->cnt() > candidate->cnt()) { + candidate = sr; + } + } + SwitchRange most_freq = *candidate; + if (most_freq.cnt() == 0) { + break; + } + + // Copy remaining ranges into another array + int shift = 0; + for (uint i = 0; i < nr; i++) { + SwitchRange* sr = &lo[i]; + if (sr != candidate) { + ranges[i-shift] = *sr; + } else { + shift++; + if (i > 0 && i < nr-1) { + SwitchRange prev = lo[i-1]; + prev.setRange(prev.lo(), sr->hi(), prev.dest(), prev.table_index(), prev.cnt()); + if (prev.adjoin(lo[i+1])) { + shift++; + i++; + } + ranges[i-shift] = prev; + } + } + } + nr -= shift; + + // Evaluate cost of testing the most common range and performing a + // binary search on the other ranges + float cost = extra + compute_tree_cost(&ranges[0], &ranges[nr-1], total_cnt); + if (cost >= min) { + break; + } + // swap arrays + lo = &ranges[0]; + hi = &ranges[nr-1]; + + // It pays off: emit the test for the most common range + assert(most_freq.cnt() > 0, "must be taken"); + Node* val = _gvn.transform(new SubINode(key_val, _gvn.intcon(most_freq.lo()))); + Node* cmp = _gvn.transform(new CmpUNode(val, _gvn.intcon(most_freq.hi() - most_freq.lo()))); + Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::le)); + IfNode* iff = create_and_map_if(control(), tst, if_prob(most_freq.cnt(), total_cnt), if_cnt(most_freq.cnt())); + jump_if_true_fork(iff, most_freq.dest(), most_freq.table_index(), false); + + sub += most_freq.cnt() / total_cnt; + extra += 1 - sub; + min = cost; + } +} + //----------------------------create_jump_tables------------------------------- bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) { // Are jumptables enabled @@ -418,6 +758,8 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) // Don't make jump table if profiling if (method_data_update()) return false; + bool trim_ranges = !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); + // Decide if a guard is needed to lop off big ranges at either (or // both) end(s) of the input set. We'll call this the default target // even though we can't be sure that it is the true "default". @@ -439,12 +781,22 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) default_dest = hi->dest(); } + float total = sum_of_cnts(lo, hi); + float cost = compute_tree_cost(lo, hi, total); + // If a guard test will eliminate very sparse end ranges, then // it is worth the cost of an extra jump. + float trimmed_cnt = 0; if (total_outlier_size > (MaxJumpTableSparseness * 4)) { needs_guard = true; - if (default_dest == lo->dest()) lo++; - if (default_dest == hi->dest()) hi--; + if (default_dest == lo->dest()) { + trimmed_cnt += lo->cnt(); + lo++; + } + if (default_dest == hi->dest()) { + trimmed_cnt += hi->cnt(); + hi--; + } } // Find the total number of cases and ranges @@ -452,8 +804,23 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) int num_range = hi - lo + 1; // Don't create table if: too large, too small, or too sparse. - if (num_cases < MinJumpTableSize || num_cases > MaxJumpTableSize) + if (num_cases > MaxJumpTableSize) return false; + if (UseSwitchProfiling) { + // MinJumpTableSize is set so with a well balanced binary tree, + // when the number of ranges is MinJumpTableSize, it's cheaper to + // go through a JumpNode that a tree of IfNodes. Average cost of a + // tree of IfNodes with MinJumpTableSize is + // log2f(MinJumpTableSize) comparisons. So if the cost computed + // from profile data is less than log2f(MinJumpTableSize) then + // going with the binary search is cheaper. + if (cost < log2f(MinJumpTableSize)) { + return false; + } + } else { + if (num_cases < MinJumpTableSize) + return false; + } if (num_cases > (MaxJumpTableSparseness * num_range)) return false; @@ -465,10 +832,12 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) // in the switch domain. if (needs_guard) { Node* size = _gvn.intcon(num_cases); - Node* cmp = _gvn.transform( new CmpUNode(key_val, size) ); - Node* tst = _gvn.transform( new BoolNode(cmp, BoolTest::ge) ); - IfNode* iff = create_and_map_if( control(), tst, PROB_FAIR, COUNT_UNKNOWN); - jump_if_true_fork(iff, default_dest, NullTableIndex); + Node* cmp = _gvn.transform(new CmpUNode(key_val, size)); + Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::ge)); + IfNode* iff = create_and_map_if(control(), tst, if_prob(trimmed_cnt, total), if_cnt(trimmed_cnt)); + jump_if_true_fork(iff, default_dest, NullTableIndex, trim_ranges && trimmed_cnt == 0); + + total -= trimmed_cnt; } // Create an ideal node JumpTable that has projections @@ -489,17 +858,44 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) key_val = _gvn.transform( new MulXNode( key_val, shiftWord)); // Create the JumpNode - Node* jtn = _gvn.transform( new JumpNode(control(), key_val, num_cases) ); + Arena* arena = C->comp_arena(); + float* probs = (float*)arena->Amalloc(sizeof(float)*num_cases); + int i = 0; + if (total == 0) { + for (SwitchRange* r = lo; r <= hi; r++) { + for (int64_t j = r->lo(); j <= r->hi(); j++, i++) { + probs[i] = 1.0F / num_cases; + } + } + } else { + for (SwitchRange* r = lo; r <= hi; r++) { + float prob = r->cnt()/total; + for (int64_t j = r->lo(); j <= r->hi(); j++, i++) { + probs[i] = prob / (r->hi() - r->lo() + 1); + } + } + } + + ciMethodData* methodData = method()->method_data(); + ciMultiBranchData* profile = NULL; + if (methodData->is_mature()) { + ciProfileData* data = methodData->bci_to_data(bci()); + if (data != NULL && data->is_MultiBranchData()) { + profile = (ciMultiBranchData*)data; + } + } + + Node* jtn = _gvn.transform(new JumpNode(control(), key_val, num_cases, probs, profile == NULL ? COUNT_UNKNOWN : total)); // These are the switch destinations hanging off the jumpnode - int i = 0; + i = 0; for (SwitchRange* r = lo; r <= hi; r++) { for (int64_t j = r->lo(); j <= r->hi(); j++, i++) { Node* input = _gvn.transform(new JumpProjNode(jtn, i, r->dest(), (int)(j - lowval))); { PreserveJVMState pjvms(this); set_control(input); - jump_if_always_fork(r->dest(), r->table_index()); + jump_if_always_fork(r->dest(), r->table_index(), trim_ranges && r->cnt() == 0); } } } @@ -511,6 +907,7 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) //----------------------------jump_switch_ranges------------------------------- void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, int switch_depth) { Block* switch_block = block(); + bool trim_ranges = !method_data_update() && !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); if (switch_depth == 0) { // Do special processing for the top-level call. @@ -519,21 +916,23 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, // Decrement pred-numbers for the unique set of nodes. #ifdef ASSERT - // Ensure that the block's successors are a (duplicate-free) set. - int successors_counted = 0; // block occurrences in [hi..lo] - int unique_successors = switch_block->num_successors(); - for (int i = 0; i < unique_successors; i++) { - Block* target = switch_block->successor_at(i); + if (!trim_ranges) { + // Ensure that the block's successors are a (duplicate-free) set. + int successors_counted = 0; // block occurrences in [hi..lo] + int unique_successors = switch_block->num_successors(); + for (int i = 0; i < unique_successors; i++) { + Block* target = switch_block->successor_at(i); - // Check that the set of successors is the same in both places. - int successors_found = 0; - for (SwitchRange* p = lo; p <= hi; p++) { - if (p->dest() == target->start()) successors_found++; + // Check that the set of successors is the same in both places. + int successors_found = 0; + for (SwitchRange* p = lo; p <= hi; p++) { + if (p->dest() == target->start()) successors_found++; + } + assert(successors_found > 0, "successor must be known"); + successors_counted += successors_found; } - assert(successors_found > 0, "successor must be known"); - successors_counted += successors_found; + assert(successors_counted == (hi-lo)+1, "no unexpected successors"); } - assert(successors_counted == (hi-lo)+1, "no unexpected successors"); #endif // Maybe prune the inputs, based on the type of key_val. @@ -545,10 +944,20 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, max_val = ti->_hi; assert(min_val <= max_val, "invalid int type"); } - while (lo->hi() < min_val) lo++; - if (lo->lo() < min_val) lo->setRange(min_val, lo->hi(), lo->dest(), lo->table_index()); - while (hi->lo() > max_val) hi--; - if (hi->hi() > max_val) hi->setRange(hi->lo(), max_val, hi->dest(), hi->table_index()); + while (lo->hi() < min_val) { + lo++; + } + if (lo->lo() < min_val) { + lo->setRange(min_val, lo->hi(), lo->dest(), lo->table_index(), lo->cnt()); + } + while (hi->lo() > max_val) { + hi--; + } + if (hi->hi() > max_val) { + hi->setRange(hi->lo(), max_val, hi->dest(), hi->table_index(), hi->cnt()); + } + + linear_search_switch_ranges(key_val, lo, hi); } #ifndef PRODUCT @@ -560,42 +969,57 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, assert(lo <= hi, "must be a non-empty set of ranges"); if (lo == hi) { - jump_if_always_fork(lo->dest(), lo->table_index()); + jump_if_always_fork(lo->dest(), lo->table_index(), trim_ranges && lo->cnt() == 0); } else { assert(lo->hi() == (lo+1)->lo()-1, "contiguous ranges"); assert(hi->lo() == (hi-1)->hi()+1, "contiguous ranges"); if (create_jump_tables(key_val, lo, hi)) return; + SwitchRange* mid = NULL; + float total_cnt = sum_of_cnts(lo, hi); + int nr = hi - lo + 1; + if (UseSwitchProfiling) { + // Don't keep the binary search tree balanced: pick up mid point + // that split frequencies in half. + float cnt = 0; + for (SwitchRange* sr = lo; sr <= hi; sr++) { + cnt += sr->cnt(); + if (cnt >= total_cnt / 2) { + mid = sr; + break; + } + } + } else { + mid = lo + nr/2; - SwitchRange* mid = lo + nr/2; - // if there is an easy choice, pivot at a singleton: - if (nr > 3 && !mid->is_singleton() && (mid-1)->is_singleton()) mid--; + // if there is an easy choice, pivot at a singleton: + if (nr > 3 && !mid->is_singleton() && (mid-1)->is_singleton()) mid--; - assert(lo < mid && mid <= hi, "good pivot choice"); - assert(nr != 2 || mid == hi, "should pick higher of 2"); - assert(nr != 3 || mid == hi-1, "should pick middle of 3"); + assert(lo < mid && mid <= hi, "good pivot choice"); + assert(nr != 2 || mid == hi, "should pick higher of 2"); + assert(nr != 3 || mid == hi-1, "should pick middle of 3"); + } - Node *test_val = _gvn.intcon(mid->lo()); + + Node *test_val = _gvn.intcon(mid == lo ? mid->hi() : mid->lo()); if (mid->is_singleton()) { - IfNode *iff_ne = jump_if_fork_int(key_val, test_val, BoolTest::ne); - jump_if_false_fork(iff_ne, mid->dest(), mid->table_index()); + IfNode *iff_ne = jump_if_fork_int(key_val, test_val, BoolTest::ne, 1-if_prob(mid->cnt(), total_cnt), if_cnt(mid->cnt())); + jump_if_false_fork(iff_ne, mid->dest(), mid->table_index(), trim_ranges && mid->cnt() == 0); // Special Case: If there are exactly three ranges, and the high // and low range each go to the same place, omit the "gt" test, // since it will not discriminate anything. - bool eq_test_only = (hi == lo+2 && hi->dest() == lo->dest()); - if (eq_test_only) { - assert(mid == hi-1, ""); - } + bool eq_test_only = (hi == lo+2 && hi->dest() == lo->dest() && mid == hi-1) || mid == lo; // if there is a higher range, test for it and process it: if (mid < hi && !eq_test_only) { // two comparisons of same values--should enable 1 test for 2 branches // Use BoolTest::le instead of BoolTest::gt - IfNode *iff_le = jump_if_fork_int(key_val, test_val, BoolTest::le); + float cnt = sum_of_cnts(lo, mid-1); + IfNode *iff_le = jump_if_fork_int(key_val, test_val, BoolTest::le, if_prob(cnt, total_cnt), if_cnt(cnt)); Node *iftrue = _gvn.transform( new IfTrueNode(iff_le) ); Node *iffalse = _gvn.transform( new IfFalseNode(iff_le) ); { PreserveJVMState pjvms(this); @@ -607,24 +1031,33 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, } else { // mid is a range, not a singleton, so treat mid..hi as a unit - IfNode *iff_ge = jump_if_fork_int(key_val, test_val, BoolTest::ge); + float cnt = sum_of_cnts(mid == lo ? mid+1 : mid, hi); + IfNode *iff_ge = jump_if_fork_int(key_val, test_val, mid == lo ? BoolTest::gt : BoolTest::ge, if_prob(cnt, total_cnt), if_cnt(cnt)); // if there is a higher range, test for it and process it: if (mid == hi) { - jump_if_true_fork(iff_ge, mid->dest(), mid->table_index()); + jump_if_true_fork(iff_ge, mid->dest(), mid->table_index(), trim_ranges && cnt == 0); } else { Node *iftrue = _gvn.transform( new IfTrueNode(iff_ge) ); Node *iffalse = _gvn.transform( new IfFalseNode(iff_ge) ); { PreserveJVMState pjvms(this); set_control(iftrue); - jump_switch_ranges(key_val, mid, hi, switch_depth+1); + jump_switch_ranges(key_val, mid == lo ? mid+1 : mid, hi, switch_depth+1); } set_control(iffalse); } } // in any case, process the lower range - jump_switch_ranges(key_val, lo, mid-1, switch_depth+1); + if (mid == lo) { + if (mid->is_singleton()) { + jump_switch_ranges(key_val, lo+1, hi, switch_depth+1); + } else { + jump_if_always_fork(lo->dest(), lo->table_index(), trim_ranges && lo->cnt() == 0); + } + } else { + jump_switch_ranges(key_val, lo, mid-1, switch_depth+1); + } } // Decrease pred_count for each successor after all is done. @@ -724,7 +1157,7 @@ void Parse::do_irem() { Node *mask = _gvn.intcon((divisor - 1)); // Sigh, must handle negative dividends Node *zero = _gvn.intcon(0); - IfNode *ifff = jump_if_fork_int(a, zero, BoolTest::lt); + IfNode *ifff = jump_if_fork_int(a, zero, BoolTest::lt, PROB_FAIR, COUNT_UNKNOWN); Node *iff = _gvn.transform( new IfFalseNode(ifff) ); Node *ift = _gvn.transform( new IfTrueNode (ifff) ); Node *reg = jump_if_join(ift, iff); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index bdd3c420bc3..16b7eb1a3ea 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -2997,6 +2997,8 @@ public: diagnostic(bool, ShowRegistersOnAssert, false, \ "On internal errors, include registers in error report.") \ \ + experimental(bool, UseSwitchProfiling, true, \ + "leverage profiling for table/lookup switch") \ #define VM_FLAGS(develop, \ develop_pd, \ diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 8ad9b2a6e5d..9e5f1294b2c 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1000,6 +1000,8 @@ typedef PaddedEnd PaddedObjectMonitor; c2_nonstatic_field(MachIfNode, _prob, jfloat) \ c2_nonstatic_field(MachIfNode, _fcnt, jfloat) \ \ + c2_nonstatic_field(MachJumpNode, _probs, jfloat*) \ + \ c2_nonstatic_field(CallNode, _entry_point, address) \ \ c2_nonstatic_field(CallJavaNode, _method, ciMethod*) \ @@ -1663,6 +1665,7 @@ typedef PaddedEnd PaddedObjectMonitor; declare_c2_type(MachNullCheckNode, MachIdealNode) \ declare_c2_type(MachProjNode, ProjNode) \ declare_c2_type(MachIfNode, MachNode) \ + declare_c2_type(MachJumpNode, MachNode) \ declare_c2_type(MachFastLockNode, MachNode) \ declare_c2_type(MachReturnNode, MachNode) \ declare_c2_type(MachSafePointNode, MachReturnNode) \ From 3b923d063e08fc8898d5483914118f523230954a Mon Sep 17 00:00:00 2001 From: Sangheon Kim Date: Tue, 24 Apr 2018 16:48:29 -0700 Subject: [PATCH 033/102] 8196325: GarbageCollectionNotificationInfo has same information for before and after Reviewed-by: mchung, sspitsyn --- .../management/ManagementFactoryHelper.java | 13 ++++++++++++- .../internal/GarbageCollectorExtImpl.java | 12 ++++-------- ...bageCollectionNotificationContentTest.java | 19 +++++++++++++++---- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java b/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java index 5336177ba50..5848c8dc2cc 100644 --- a/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java +++ b/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ import java.util.List; import java.lang.reflect.UndeclaredThrowableException; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -162,6 +163,16 @@ public class ManagementFactoryHelper { return LoggingMXBeanAccess.isAvailable(); } + /** + * Returns an array of the name of all memory pools. The order of the memory pools is + * significant and maintained in the VM. + */ + public static String[] getAllMemoryPoolNames() { + return Arrays.stream(MemoryImpl.getMemoryPools()) + .map(MemoryPoolMXBean::getName) + .toArray(String[]::new); + } + // The LoggingMXBeanAccess class uses reflection to determine // whether java.util.logging is present, and load the actual LoggingMXBean // implementation. diff --git a/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectorExtImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectorExtImpl.java index fde7a0070df..dadc5f91ca2 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectorExtImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectorExtImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package com.sun.management.internal; import com.sun.management.GarbageCollectionNotificationInfo; import com.sun.management.GarbageCollectorMXBean; import com.sun.management.GcInfo; -import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; import java.util.List; import javax.management.ListenerNotFoundException; @@ -38,6 +37,7 @@ import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.openmbean.CompositeData; import sun.management.GarbageCollectorImpl; +import sun.management.ManagementFactoryHelper; /** * Implementation class for the garbage collector. @@ -59,12 +59,8 @@ public class GarbageCollectorExtImpl extends GarbageCollectorImpl private String[] poolNames = null; private synchronized String[] getAllPoolNames() { if (poolNames == null) { - List pools = ManagementFactory.getMemoryPoolMXBeans(); - poolNames = new String[pools.size()]; - int i = 0; - for (MemoryPoolMXBean m : pools) { - poolNames[i++] = m.getName(); - } + // The order of all memory pool names is important as GcInfo is also created with same order. + poolNames = ManagementFactoryHelper.getAllMemoryPoolNames(); } return poolNames; } diff --git a/test/jdk/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java b/test/jdk/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java index d5df6a34135..ec05aa9ed15 100644 --- a/test/jdk/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java +++ b/test/jdk/com/sun/management/GarbageCollectorMXBean/GarbageCollectionNotificationContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,8 @@ * @requires vm.opt.ExplicitGCInvokesConcurrent == null | vm.opt.ExplicitGCInvokesConcurrent == false * @modules java.management/sun.management * jdk.management - * @run main/othervm GarbageCollectionNotificationContentTest - */ + * @run main/othervm -Xms64m -Xmx64m GarbageCollectionNotificationContentTest + */ import java.util.*; import java.lang.management.*; @@ -97,7 +97,7 @@ public class GarbageCollectionNotificationContentTest { System.gc(); // Allocation of many short living and small objects to trigger minor GC Object data[] = new Object[32]; - for(int i = 0; i<100000000; i++) { + for(int i = 0; i<10000000; i++) { data[i%32] = new int[8]; } int wakeup = 0; @@ -139,6 +139,8 @@ public class GarbageCollectionNotificationContentTest { System.out.println("Usage for pool " + poolname); System.out.println(" Before GC: " + busage); System.out.println(" After GC: " + ausage); + + checkMemoryUsage(poolname, busage, ausage); } // check if memory usage for all memory pools are returned @@ -150,4 +152,13 @@ public class GarbageCollectionNotificationContentTest { } } } + + private static void checkMemoryUsage(String poolname, MemoryUsage busage, MemoryUsage ausage) throws Exception { + if (poolname.contains("Eden Space") && busage.getUsed() > 0) { + // Used size at Eden Space should be decreased or + if (busage.getUsed() <= ausage.getUsed()) { + throw new RuntimeException("Used size at Eden Space should be decreased."); + } + } + } } From 3dfa260af9f04144d8101b2a57ca344eb2351aa1 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 24 Apr 2018 11:54:03 -0700 Subject: [PATCH 034/102] 8025091: VisibleMemberMap.java possible performance improvements 8198890: The standard doclet incorrectly produces wrong method signatures in certain cases Reviewed-by: jjg --- .../formats/html/AbstractMemberWriter.java | 4 +- .../html/AnnotationTypeFieldWriterImpl.java | 2 - .../html/AnnotationTypeWriterImpl.java | 2 - .../doclets/formats/html/ClassWriterImpl.java | 13 +- .../formats/html/ConstructorWriterImpl.java | 12 +- .../doclets/formats/html/Contents.java | 24 +- .../doclets/formats/html/HtmlDoclet.java | 5 +- .../formats/html/HtmlDocletWriter.java | 35 +- .../formats/html/MethodWriterImpl.java | 11 +- .../formats/html/WriterFactoryImpl.java | 9 +- .../formats/html/markup/Navigation.java | 78 +- .../doclets/toolkit/AbstractDoclet.java | 8 +- .../doclets/toolkit/BaseConfiguration.java | 55 +- .../doclets/toolkit/MemberSummaryWriter.java | 3 +- .../doclets/toolkit/PropertyUtils.java | 172 +++ .../doclets/toolkit/WriterFactory.java | 17 +- .../builders/AbstractMemberBuilder.java | 26 +- .../builders/AnnotationTypeFieldBuilder.java | 26 +- .../AnnotationTypeOptionalMemberBuilder.java | 7 +- .../AnnotationTypeRequiredMemberBuilder.java | 27 +- .../builders/ConstantsSummaryBuilder.java | 32 +- .../toolkit/builders/ConstructorBuilder.java | 23 +- .../toolkit/builders/EnumConstantBuilder.java | 23 +- .../toolkit/builders/FieldBuilder.java | 27 +- .../builders/MemberSummaryBuilder.java | 289 ++--- .../toolkit/builders/MethodBuilder.java | 23 +- .../toolkit/builders/PropertyBuilder.java | 24 +- .../toolkit/resources/doclets.properties | 1 - .../toolkit/resources/doclets_ja.properties | 1 - .../resources/doclets_zh_CN.properties | 1 - .../toolkit/taglets/TagletManager.java | 6 +- .../doclets/toolkit/util/ClassTree.java | 5 +- .../doclets/toolkit/util/ClassUseMapper.java | 12 +- .../doclets/toolkit/util/DocFinder.java | 9 +- .../toolkit/util/ImplementedMethods.java | 148 --- .../doclets/toolkit/util/IndexBuilder.java | 11 +- .../internal/doclets/toolkit/util/Utils.java | 42 +- .../toolkit/util/VisibleMemberCache.java | 57 + .../toolkit/util/VisibleMemberMap.java | 842 --------------- .../toolkit/util/VisibleMemberTable.java | 992 ++++++++++++++++++ .../doclet/testJavaFX/TestFxProperties.java | 114 ++ .../javadoc/doclet/testJavaFX/TestJavaFX.java | 7 +- .../jdk/javadoc/doclet/testJavaFX/pkg1/C.java | 17 +- .../doclet/testJavaFX/propgen/PropGen.java | 129 +++ .../doclet/testOptions/TestOptions.java | 2 + .../doclet/testOrdering/TestOrdering.java | 1 + .../TestOverrideMethods.java | 3 + .../doclet/testProperty/TestProperty.java | 2 + .../javadoc/doclet/testSearch/TestSearch.java | 1 + .../TestVisibleMembers.java | 685 ++++++++++++ .../tools/lib/builder/AbstractBuilder.java | 257 +++++ .../tools/lib/builder/ClassBuilder.java | 666 ++++++++++++ 52 files changed, 3527 insertions(+), 1461 deletions(-) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ImplementedMethods.java create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberCache.java delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java create mode 100644 test/langtools/jdk/javadoc/doclet/testJavaFX/TestFxProperties.java create mode 100644 test/langtools/jdk/javadoc/doclet/testJavaFX/propgen/PropGen.java create mode 100644 test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java create mode 100644 test/langtools/tools/lib/builder/AbstractBuilder.java create mode 100644 test/langtools/tools/lib/builder/ClassBuilder.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index 1809daa9c10..27e7c0d15d7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -45,14 +45,12 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Links; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet; import jdk.javadoc.internal.doclets.toolkit.util.Utils; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; import static javax.lang.model.element.Modifier.*; @@ -134,7 +132,7 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter { /** * Create the summary table for this element. * The table should be created and initialized if needed, and configured - * so that it is ready to add content with {@link Table#addRows(Content[])} + * so that it is ready to add content with {@link Table#addRow(Content[])} * and similar methods. * * @return the summary table diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java index 7de6932ef9c..65c4c7503a2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java @@ -37,13 +37,11 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; - /** * Writes annotation type field documentation in HTML format. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java index 6f8309c76ac..8d48a554e2d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java @@ -41,10 +41,8 @@ import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; /** * Generate the Class Information Page. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java index 7b88d5c1f79..a8614f9eee6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java @@ -45,14 +45,11 @@ import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.ClassWriter; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder; import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; -import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; /** * Generate the Class Information Page. @@ -122,7 +119,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite Content moduleNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classModuleLabel); moduleNameDiv.addContent(Contents.SPACE); moduleNameDiv.addContent(getModuleLink(mdle, - new StringContent(mdle.getQualifiedName().toString()))); + new StringContent(mdle.getQualifiedName()))); div.addContent(moduleNameDiv); } PackageElement pkg = utils.containingPackage(typeElement); @@ -373,8 +370,8 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite @Override public void addSubClassInfo(Content classInfoTree) { if (utils.isClass(typeElement)) { - if (typeElement.getQualifiedName().toString().equals("java.lang.Object") || - typeElement.getQualifiedName().toString().equals("org.omg.CORBA.Object")) { + if (typeElement.getQualifiedName().contentEquals("java.lang.Object") || + typeElement.getQualifiedName().contentEquals("org.omg.CORBA.Object")) { return; // Don't generate the list, too huge } Set subclasses = classtree.directSubClasses(typeElement, false); @@ -415,8 +412,8 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite if (!utils.isInterface(typeElement)) { return; } - if (typeElement.getQualifiedName().toString().equals("java.lang.Cloneable") || - typeElement.getQualifiedName().toString().equals("java.io.Serializable")) { + if (typeElement.getQualifiedName().contentEquals("java.lang.Cloneable") || + typeElement.getQualifiedName().contentEquals("java.io.Serializable")) { return; // Don't generate the list, too big } Set implcl = classtree.implementingClasses(typeElement); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java index b0a9bc4e9be..c0536c8e3fa 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java @@ -38,12 +38,13 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.ConstructorWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; + +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** @@ -72,10 +73,9 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter public ConstructorWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { super(writer, typeElement); - VisibleMemberMap visibleMemberMap = configuration.getVisibleMemberMap( - typeElement, - VisibleMemberMap.Kind.CONSTRUCTORS); - List constructors = visibleMemberMap.getMembers(typeElement); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(typeElement); + List constructors = vmt.getVisibleMembers(CONSTRUCTORS); + for (Element constructor : constructors) { if (utils.isProtected(constructor) || utils.isPrivate(constructor)) { setFoundNonPubConstructor(true); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java index 17ac60c81cd..636278a0edd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package jdk.javadoc.internal.doclets.formats.html; +import java.util.EnumMap; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -36,6 +38,8 @@ import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; + /** * Constants and factory methods for common fragments of content @@ -165,6 +169,8 @@ public class Contents { public final Content useLabel; public final Content valueLabel; + private final EnumMap navLinkLabels; + private final Resources resources; /** @@ -289,6 +295,13 @@ public class Contents { typeLabel = getContent("doclet.Type"); useLabel = getContent("doclet.navClassUse"); valueLabel = getContent("doclet.Value"); + + navLinkLabels = new EnumMap<>(VisibleMemberTable.Kind.class); + navLinkLabels.put(VisibleMemberTable.Kind.INNER_CLASSES, getContent("doclet.navNested")); + navLinkLabels.put(VisibleMemberTable.Kind.ENUM_CONSTANTS, getContent("doclet.navEnum")); + navLinkLabels.put(VisibleMemberTable.Kind.FIELDS, getContent("doclet.navField")); + navLinkLabels.put(VisibleMemberTable.Kind.CONSTRUCTORS, getContent("doclet.navConstructor")); + navLinkLabels.put(VisibleMemberTable.Kind.METHODS, getContent("doclet.navMethod")); } /** @@ -393,4 +406,13 @@ public class Contents { c.addContent(text.substring(start)); return c; // TODO: should be made immutable } + + /** + * Returns a content for a visible member kind. + * @param kind the visible member table kind. + * @return the string content + */ + public Content getNavLinkLabelContent(VisibleMemberTable.Kind kind) { + return Objects.requireNonNull(navLinkLabels.get(kind)); + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index c53e4c5ba3b..632dca46e19 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,7 +107,6 @@ public class HtmlDoclet extends AbstractDoclet { * For new format. * * @throws DocletException if there is a problem while writing the other files - * @see jdk.doclet.DocletEnvironment */ @Override // defined by AbstractDoclet protected void generateOtherFiles(DocletEnvironment docEnv, ClassTree classtree) @@ -242,7 +241,7 @@ public class HtmlDoclet extends AbstractDoclet { List list = new ArrayList<>(arr); ListIterator iterator = list.listIterator(); for (TypeElement klass : list) { - if (utils.isHidden(klass) || + if (utils.hasHiddenTag(klass) || !(configuration.isGeneratedDoc(klass) && utils.isIncluded(klass))) { continue; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 6cc62a8f258..7772aadf19a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -69,13 +69,11 @@ import com.sun.source.util.SimpleDocTreeVisitor; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.DocType; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Links; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; import jdk.javadoc.internal.doclets.formats.html.markup.Script; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; @@ -94,9 +92,8 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; -import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods; import jdk.javadoc.internal.doclets.toolkit.util.Utils; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import static com.sun.source.doctree.DocTree.Kind.*; import static jdk.javadoc.internal.doclets.toolkit.util.CommentHelper.SPACER; @@ -302,11 +299,12 @@ public class HtmlDocletWriter { TypeElement enclosing = utils.getEnclosingTypeElement(method); List intfacs = enclosing.getInterfaces(); ExecutableElement overriddenMethod = utils.overriddenMethod(method); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(enclosing); // Check whether there is any implementation or overridden info to be // printed. If no overridden or implementation info needs to be // printed, do not print this section. if ((!intfacs.isEmpty() - && new ImplementedMethods(method, this.configuration).build().isEmpty() == false) + && vmt.getImplementedMethods(method).isEmpty() == false) || overriddenMethod != null) { MethodWriterImpl.addImplementsInfo(this, method, dl); if (overriddenMethod != null) { @@ -1078,10 +1076,11 @@ public class HtmlDocletWriter { // Find the enclosing type where the method is actually visible // in the inheritance hierarchy. + ExecutableElement overriddenMethod = null; if (refMem.getKind() == ElementKind.METHOD) { - VisibleMemberMap vmm = configuration.getVisibleMemberMap(containing, - VisibleMemberMap.Kind.METHODS); - ExecutableElement overriddenMethod = vmm.getVisibleMethod((ExecutableElement)refMem); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(containing); + overriddenMethod = vmt.getOverriddenMethod((ExecutableElement)refMem); + if (overriddenMethod != null) containing = utils.getEnclosingTypeElement(overriddenMethod); } @@ -1112,6 +1111,10 @@ public class HtmlDocletWriter { if (refMemName.indexOf('(') < 0) { refMemName += utils.makeSignature((ExecutableElement)refMem, true); } + if (overriddenMethod != null) { + // The method to actually link. + refMem = overriddenMethod; + } } text = plainOrCode(kind == LINK_PLAIN, new StringContent(refMemName)); @@ -1596,7 +1599,7 @@ public class HtmlDocletWriter { * {@literal The package Page} * * @param element the Element object whose documentation is being written. - * @param text the text being written. + * @param tt the text being written. * * @return the text, with all the relative links redirected to work. */ @@ -1671,7 +1674,7 @@ public class HtmlDocletWriter { * Add the annotation types of the executable receiver. * * @param method the executable to write the receiver annotations for. - * @param descList list of annotation description. + * @param descList a list of annotation mirrors. * @param htmltree the documentation tree to which the annotation info will be * added */ @@ -1718,7 +1721,7 @@ public class HtmlDocletWriter { * Adds the annotatation types for the given Element. * * @param element the element to write annotations for. - * @param descList the array of {@link AnnotationDesc}. + * @param descList a list of annotation mirrors. * @param htmltree the documentation tree to which the annotation info will be * added */ @@ -1732,7 +1735,7 @@ public class HtmlDocletWriter { * * @param indent the number of extra spaces to indent the annotations. * @param element the element to write annotations for. - * @param descList the array of {@link AnnotationDesc}. + * @param descList a list of annotation mirrors. * @param htmltree the documentation tree to which the annotation info will be * added */ @@ -1758,9 +1761,9 @@ public class HtmlDocletWriter { * the given doc. * * @param indent the number of extra spaces to indent the annotations. - * @param descList the array of {@link AnnotationDesc}. + * @param descList a list of annotation mirrors. * @param linkBreak if true, add new line between each member value. - * @return an array of strings representing the annotations being + * @return a list of strings representing the annotations being * documented. */ private List getAnnotations(int indent, List descList, boolean linkBreak) { @@ -1781,10 +1784,10 @@ public class HtmlDocletWriter { * annotations should be returned without any filtering. * * @param indent the number of extra spaces to indent the annotations. - * @param descList the array of {@link AnnotationDesc}. + * @param descList a list of annotation mirrors. * @param linkBreak if true, add new line between each member value. * @param isJava5DeclarationLocation - * @return an array of strings representing the annotations being + * @return a list of strings representing the annotations being * documented. */ public List getAnnotations(int indent, List descList, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java index 00f8784b963..94846f8f93e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java @@ -40,13 +40,12 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Navigation; import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; import jdk.javadoc.internal.doclets.toolkit.MethodWriter; -import jdk.javadoc.internal.doclets.toolkit.util.ImplementedMethods; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; /** * Writes method documentation in HTML format. @@ -383,13 +382,13 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter return; } Contents contents = writer.contents; - ImplementedMethods implementedMethodsFinder = - new ImplementedMethods(method, writer.configuration); + VisibleMemberTable vmt = writer.configuration + .getVisibleMemberTable(utils.getEnclosingTypeElement(method)); SortedSet implementedMethods = new TreeSet<>(utils.makeOverrideUseComparator()); - implementedMethods.addAll(implementedMethodsFinder.build()); + implementedMethods.addAll(vmt.getImplementedMethods(method)); for (ExecutableElement implementedMeth : implementedMethods) { - TypeMirror intfac = implementedMethodsFinder.getMethodHolder(implementedMeth); + TypeMirror intfac = vmt.getImplementedMethodHolder(method, implementedMeth); intfac = utils.getDeclaredType(utils.getEnclosingTypeElement(method), intfac); Content intfaclink = writer.getLink(new LinkInfoImpl( writer.configuration, LinkInfoImpl.Kind.METHOD_SPECIFIED_BY, intfac)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java index 76c7bb74cfc..acdaaedd017 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/WriterFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeMirror; import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter; import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter; @@ -45,7 +44,7 @@ import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter; import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter; import jdk.javadoc.internal.doclets.toolkit.WriterFactory; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; /** * The factory that returns HTML writers. @@ -184,7 +183,7 @@ public class WriterFactoryImpl implements WriterFactory { */ @Override public MemberSummaryWriter getMemberSummaryWriter(ClassWriter classWriter, - VisibleMemberMap.Kind memberType) { + VisibleMemberTable.Kind memberType) { switch (memberType) { case CONSTRUCTORS: return getConstructorWriter(classWriter); @@ -209,7 +208,7 @@ public class WriterFactoryImpl implements WriterFactory { */ @Override public MemberSummaryWriter getMemberSummaryWriter(AnnotationTypeWriter annotationTypeWriter, - VisibleMemberMap.Kind memberType) { + VisibleMemberTable.Kind memberType) { switch (memberType) { case ANNOTATION_TYPE_FIELDS: return (AnnotationTypeFieldWriterImpl) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java index 244a9eb1346..b8dc77c51d5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java @@ -30,6 +30,7 @@ import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SortedSet; import javax.lang.model.element.Element; @@ -48,7 +49,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; + +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Factory for navigation bar. @@ -414,28 +417,28 @@ public class Navigation { case CLASS: if (element.getKind() == ElementKind.ANNOTATION_TYPE) { addAnnotationTypeSummaryLink("doclet.navField", - VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, listContents); + ANNOTATION_TYPE_FIELDS, listContents); addAnnotationTypeSummaryLink("doclet.navAnnotationTypeRequiredMember", - VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, listContents); + ANNOTATION_TYPE_MEMBER_REQUIRED, listContents); addAnnotationTypeSummaryLink("doclet.navAnnotationTypeOptionalMember", - VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, listContents); + ANNOTATION_TYPE_MEMBER_OPTIONAL, listContents); } else { TypeElement typeElement = (TypeElement) element; - for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) { - if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) { + for (VisibleMemberTable.Kind kind : summarySet) { + if (kind == ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) { continue; } - if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && configuration.utils.isEnum(typeElement)) { + if (kind == CONSTRUCTORS && configuration.utils.isEnum(typeElement)) { continue; } AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind)); if (writer == null) { - addContentToList(listContents, - contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind))); + addContentToList(listContents, contents.getNavLinkLabelContent(kind)); } else { addTypeSummaryLink(memberSummaryBuilder.members(kind), - memberSummaryBuilder.getVisibleMemberMap(kind), listContents); + memberSummaryBuilder.getVisibleMemberTable(), + kind, listContents); } } } @@ -487,24 +490,25 @@ public class Navigation { * Add the navigation summary link. * * @param members members to be linked - * @param visibleMemberMap the visible inherited members map + * @param vmt the visible member table + * @param kind the visible member kind * @param listContents the list of contents */ private void addTypeSummaryLink(SortedSet members, - VisibleMemberMap visibleMemberMap, List listContents) { + VisibleMemberTable vmt, + VisibleMemberTable.Kind kind, List listContents) { if (!members.isEmpty()) { - addTypeSummaryLink(null, visibleMemberMap.kind, true, listContents); + addTypeSummaryLink(null, kind, true, listContents); return; } - - SortedSet visibleClasses = visibleMemberMap.getVisibleClasses(); + Set visibleClasses = vmt.getVisibleTypeElements(); for (TypeElement t : visibleClasses) { - if (!configuration.getVisibleMemberMap(t, visibleMemberMap.kind).getLeafMembers().isEmpty()) { - addTypeSummaryLink(null, visibleMemberMap.kind, true, listContents); + if (configuration.getVisibleMemberTable(t).hasVisibleMembers(kind)) { + addTypeSummaryLink(null, kind, true, listContents); return; } } - addTypeSummaryLink(null, visibleMemberMap.kind, false, listContents); + addTypeSummaryLink(null, kind, false, listContents); } /** @@ -515,7 +519,7 @@ public class Navigation { * @param link true if the members are listed and need to be linked * @param listContents the list of contents to which the summary will be added */ - private void addTypeSummaryLink(TypeElement typeElement, VisibleMemberMap.Kind kind, boolean link, + private void addTypeSummaryLink(TypeElement typeElement, VisibleMemberTable.Kind kind, boolean link, List listContents) { switch (kind) { case CONSTRUCTORS: @@ -601,17 +605,17 @@ public class Navigation { * Add the navigation Type summary link. * * @param label the label to be added - * @param type the kind of member being documented + * @param kind the kind of member being documented * @param listContents the list of contents to which the summary will be added */ - private void addAnnotationTypeSummaryLink(String label, VisibleMemberMap.Kind type, List listContents) { + private void addAnnotationTypeSummaryLink(String label, VisibleMemberTable.Kind kind, List listContents) { AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder. - getMemberSummaryWriter(type)); + getMemberSummaryWriter(kind)); if (writer == null) { addContentToList(listContents, contents.getContent(label)); } else { - boolean link = !memberSummaryBuilder.getVisibleMemberMap(type).noVisibleMembers(); - switch (type) { + boolean link = memberSummaryBuilder.getVisibleMemberTable().hasVisibleMembers(kind); + switch (kind) { case ANNOTATION_TYPE_FIELDS: if (link) { addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_FIELD_SUMMARY, @@ -657,20 +661,20 @@ public class Navigation { addAnnotationTypeDetailLink(listContents); } else { TypeElement typeElement = (TypeElement) element; - for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) { + for (VisibleMemberTable.Kind kind : detailSet) { AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder. getMemberSummaryWriter(kind)); - if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) { + if (kind == ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) { continue; } - if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && configuration.utils.isEnum(typeElement)) { + if (kind == CONSTRUCTORS && configuration.utils.isEnum(typeElement)) { continue; } if (writer == null) { - addContentToList(listContents, contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind))); + addContentToList(listContents, contents.getNavLinkLabelContent(kind)); } else { - addTypeDetailLink(kind, !memberSummaryBuilder.members(kind).isEmpty(), listContents); + addTypeDetailLink(kind, memberSummaryBuilder.hasMembers(kind), listContents); } } } @@ -693,7 +697,7 @@ public class Navigation { * @param link true if the members are listed and need to be linked * @param listContents the list of contents to which the detail will be added. */ - protected void addTypeDetailLink(VisibleMemberMap.Kind kind, boolean link, List listContents) { + protected void addTypeDetailLink(VisibleMemberTable.Kind kind, boolean link, List listContents) { switch (kind) { case CONSTRUCTORS: if (link) { @@ -744,25 +748,25 @@ public class Navigation { TypeElement annotationType = (TypeElement) element; AbstractMemberWriter writerField = ((AbstractMemberWriter) memberSummaryBuilder. - getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS)); + getMemberSummaryWriter(ANNOTATION_TYPE_FIELDS)); AbstractMemberWriter writerOptional = ((AbstractMemberWriter) memberSummaryBuilder. - getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL)); + getMemberSummaryWriter(ANNOTATION_TYPE_MEMBER_OPTIONAL)); AbstractMemberWriter writerRequired = ((AbstractMemberWriter) memberSummaryBuilder. - getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED)); + getMemberSummaryWriter(ANNOTATION_TYPE_MEMBER_REQUIRED)); if (writerField != null) { - addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, + addAnnotationTypeDetailLink(ANNOTATION_TYPE_FIELDS, !configuration.utils.getAnnotationFields(annotationType).isEmpty(), listContents); } else { addContentToList(listContents, contents.navField); } if (writerOptional != null) { - addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, + addAnnotationTypeDetailLink(ANNOTATION_TYPE_MEMBER_OPTIONAL, !annotationType.getAnnotationMirrors().isEmpty(), listContents); } else if (writerRequired != null) { - addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, + addAnnotationTypeDetailLink(ANNOTATION_TYPE_MEMBER_REQUIRED, !annotationType.getAnnotationMirrors().isEmpty(), listContents); } else { addContentToList(listContents, contents.navAnnotationTypeMember); @@ -776,7 +780,7 @@ public class Navigation { * @param link true if the member details need to be linked * @param listContents the list of contents to which the annotation detail will be added. */ - protected void addAnnotationTypeDetailLink(VisibleMemberMap.Kind type, boolean link, List listContents) { + protected void addAnnotationTypeDetailLink(VisibleMemberTable.Kind type, boolean link, List listContents) { switch (type) { case ANNOTATION_TYPE_FIELDS: if (link) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java index 34f48389e97..a6afb3feada 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ public abstract class AbstractDoclet implements Doclet { /** * Verify that the only doclet that is using this toolkit is - * {@value #TOOLKIT_DOCLET_NAME}. + * #TOOLKIT_DOCLET_NAME. */ private boolean isValidDoclet() { if (!getClass().getName().equals(TOOLKIT_DOCLET_NAME)) { @@ -102,10 +102,7 @@ public abstract class AbstractDoclet implements Doclet { public boolean run(DocletEnvironment docEnv) { configuration = getConfiguration(); configuration.initConfiguration(docEnv); - configuration.cmtUtils = new CommentUtils(configuration); - configuration.utils = new Utils(configuration); utils = configuration.utils; - configuration.workArounds = new WorkArounds(configuration); messages = configuration.getMessages(); if (!isValidDoclet()) { @@ -189,7 +186,6 @@ public abstract class AbstractDoclet implements Doclet { * TreeWriter generation first to ensure the Class Hierarchy is built * first and then can be used in the later generation. * - * @see jdk.doclet.DocletEnvironment * @throws DocletException if there is a problem while generating the documentation */ private void startGeneration(DocletEnvironment docEnv) throws DocletException { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java index 646a605934d..3f6e90d5e29 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java @@ -26,7 +26,6 @@ package jdk.javadoc.internal.doclets.toolkit; import java.io.*; -import java.lang.ref.*; import java.util.*; import javax.lang.model.element.Element; @@ -56,9 +55,8 @@ import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException; import jdk.javadoc.internal.doclets.toolkit.util.TypeElementCatalog; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.Utils.Pair; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.GetterSetter; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberCache; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import static javax.tools.Diagnostic.Kind.*; @@ -299,8 +297,6 @@ public abstract class BaseConfiguration { private List> groupPairs; - private final Map>> typeElementMemberCache; - public abstract Messages getMessages(); public abstract Resources getResources(); @@ -331,11 +327,6 @@ public abstract class BaseConfiguration { public OverviewElement overviewElement; - // The following three fields provide caches for use by all instances of VisibleMemberMap. - public final Map> propertiesCache = new HashMap<>(); - public final Map classPropertiesMap = new HashMap<>(); - public final Map getterSetterMap = new HashMap<>(); - public DocFileFactory docFileFactory; /** @@ -351,6 +342,17 @@ public abstract class BaseConfiguration { protected static final String sharedResourceBundleName = "jdk.javadoc.internal.doclets.toolkit.resources.doclets"; + /** + * Primarily used to disable strict checks in the regression + * tests allowing those tests to be executed successfully, for + * instance, with OpenJDK builds which may not contain FX libraries. + */ + public boolean disableJavaFxStrictChecks = false; + + VisibleMemberCache visibleMemberCache = null; + + public PropertyUtils propertyUtils = null; + /** * Constructs the configurations needed by the doclet. * @@ -363,7 +365,6 @@ public abstract class BaseConfiguration { setTabWidth(DocletConstants.DEFAULT_TAB_STOP_LENGTH); metakeywords = new MetaKeywords(this); groupPairs = new ArrayList<>(0); - typeElementMemberCache = new HashMap<>(); } private boolean initialized = false; @@ -374,6 +375,15 @@ public abstract class BaseConfiguration { } initialized = true; this.docEnv = docEnv; + // Utils needs docEnv, safe to init now. + utils = new Utils(this); + + // Once docEnv and Utils have been initialized, others should be safe. + cmtUtils = new CommentUtils(this); + workArounds = new WorkArounds(this); + visibleMemberCache = new VisibleMemberCache(this); + propertyUtils = new PropertyUtils(this); + Splitter specifiedSplitter = new Splitter(docEnv, false); specifiedModuleElements = Collections.unmodifiableSet(specifiedSplitter.mset); specifiedPackageElements = Collections.unmodifiableSet(specifiedSplitter.pset); @@ -699,6 +709,13 @@ public abstract class BaseConfiguration { allowScriptInComments = true; return true; } + }, + new Hidden(resources, "--disable-javafx-strict-checks") { + @Override + public boolean process(String opt, List args) { + disableJavaFxStrictChecks = true; + return true; + } } }; Set set = new TreeSet<>(); @@ -1285,17 +1302,7 @@ public abstract class BaseConfiguration { return allowScriptInComments; } - public VisibleMemberMap getVisibleMemberMap(TypeElement te, VisibleMemberMap.Kind kind) { - EnumMap> cacheMap = typeElementMemberCache - .computeIfAbsent(te, k -> new EnumMap<>(VisibleMemberMap.Kind.class)); - - Reference vmapRef = cacheMap.get(kind); - // recompute, if referent has been garbage collected - VisibleMemberMap vMap = vmapRef == null ? null : vmapRef.get(); - if (vMap == null) { - vMap = new VisibleMemberMap(te, kind, this); - cacheMap.put(kind, new SoftReference<>(vMap)); - } - return vMap; + public synchronized VisibleMemberTable getVisibleMemberTable(TypeElement te) { + return visibleMemberCache.getVisibleMemberTable(te); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MemberSummaryWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MemberSummaryWriter.java index aab67aa0b42..b8df8133469 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MemberSummaryWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/MemberSummaryWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DocTree; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; /** * The interface for writing member summary output. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java new file mode 100644 index 00000000000..be817c0b2f4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PropertyUtils.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.toolkit; + +import java.util.regex.Pattern; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; + +/** + * This class provides basic JavaFX property related utility methods. + * Refer to the JavaFX conventions in the VisibleMemberTable comments. + */ +public class PropertyUtils { + + final TypeMirror jbObservableType; + + final Pattern fxMethodPatterns; + + final boolean javafx; + + final Types typeUtils; + + PropertyUtils(BaseConfiguration configuration) { + + javafx = configuration.javafx; + + typeUtils = configuration.docEnv.getTypeUtils(); + + // Disable strict check for JDK's without FX. + TypeMirror jboType = configuration.disableJavaFxStrictChecks + ? null + : configuration.utils.getSymbol("javafx.beans.Observable"); + + jbObservableType = jboType != null + ? configuration.docEnv.getTypeUtils().erasure(jboType) + : null; + + fxMethodPatterns = javafx + ? Pattern.compile("[sg]et\\p{Upper}.*||is\\p{Upper}.*") + : null; + } + + /** + * Returns a base name for a property method. Supposing we + * have {@code BooleanProperty acmeProperty()}, then "acme" + * will be returned. + * @param propertyMethod + * @return the base name of a property method. + */ + public String getBaseName(ExecutableElement propertyMethod) { + String name = propertyMethod.getSimpleName().toString(); + String baseName = name.substring(0, name.indexOf("Property")); + return baseName; + } + + /** + * Returns a property getter's name. Supposing we have a property + * method {@code DoubleProperty acmeProperty()}, then "getAcme" + * will be returned. + * @param propertyMethod + * @return the property getter's name. + */ + public String getGetName(ExecutableElement propertyMethod) { + String baseName = getBaseName(propertyMethod); + String fnUppercased = "" + + Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + return "get" + fnUppercased; + } + + /** + * Returns an "is" method's name for a property method. Supposing + * we have a property method {@code BooleanProperty acmeProperty()}, + * then "isAcme" will be returned. + * @param propertyMethod + * @return the property is getter's name. + */ + public String getIsName(ExecutableElement propertyMethod) { + String baseName = getBaseName(propertyMethod); + String fnUppercased = "" + + Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + return "is" + fnUppercased; + } + + /** + * Returns true if a property method could have an "is" method, meaning + * {@code isAcme} could exist for a property method. + * @param propertyMethod + * @return true if the property could have an "is" method, false otherwise. + */ + public boolean hasIsMethod(ExecutableElement propertyMethod) { + String propertyTypeName = propertyMethod.getReturnType().toString(); + return "boolean".equals(propertyTypeName) || + propertyTypeName.endsWith("BooleanProperty"); + } + + /** + * Returns a property setter's name. Supposing we have a property + * method {@code DoubleProperty acmeProperty()}, then "setAcme" + * will be returned. + * @param propertyMethod + * @return the property setter's method name. + */ + public String getSetName(ExecutableElement propertyMethod) { + String baseName = getBaseName(propertyMethod); + String fnUppercased = "" + + Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); + return "set" + fnUppercased; + } + + /** + * Returns true if the given setter method is a valid property setter + * method. + * @param setterMethod + * @return true if setter method, false otherwise. + */ + public boolean isValidSetterMethod(ExecutableElement setterMethod) { + return setterMethod.getReturnType().getKind() == TypeKind.VOID; + } + + /** + * Returns true if the method is a property method. + * @param propertyMethod + * @return true if the method is a property method, false otherwise. + */ + public boolean isPropertyMethod(ExecutableElement propertyMethod) { + if (!javafx || + !propertyMethod.getParameters().isEmpty() || + !propertyMethod.getTypeParameters().isEmpty()) { + return false; + } + String methodName = propertyMethod.getSimpleName().toString(); + if (!methodName.endsWith("Property") || + fxMethodPatterns.matcher(methodName).matches()) { + return false; + } + + TypeMirror returnType = propertyMethod.getReturnType(); + if (jbObservableType == null) { + // JavaFX references missing, make a lazy backward compatible check. + return returnType.getKind() != TypeKind.VOID; + } else { + // Apply strict checks since JavaFX references are available + returnType = typeUtils.erasure(propertyMethod.getReturnType()); + return typeUtils.isAssignable(returnType, jbObservableType); + } + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WriterFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WriterFactory.java index 9026c2cbdb8..43d8ab60f19 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WriterFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WriterFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,10 +29,9 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeMirror; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; /** * The interface for a factory creates writers. @@ -180,30 +179,30 @@ public interface WriterFactory { * Return the specified member summary writer for a given class. * * @param classWriter the writer for the class being documented. - * @param memberType the {@link VisibleMemberMap} member type indicating + * @param memberType the {@link VisibleMemberTable} member type indicating * the type of member summary that should be returned. * @return the summary writer for the give class. Return null if this * writer is not supported by the doclet. * - * @see VisibleMemberMap + * @see VisibleMemberTable */ public abstract MemberSummaryWriter getMemberSummaryWriter( - ClassWriter classWriter, VisibleMemberMap.Kind memberType); + ClassWriter classWriter, VisibleMemberTable.Kind memberType); /** * Return the specified member summary writer for a given annotation type. * * @param annotationTypeWriter the writer for the annotation type being * documented. - * @param memberType the {@link VisibleMemberMap} member type indicating + * @param memberType the {@link VisibleMemberTable} member type indicating * the type of member summary that should be returned. * @return the summary writer for the give class. Return null if this * writer is not supported by the doclet. * - * @see VisibleMemberMap + * @see VisibleMemberTable */ public abstract MemberSummaryWriter getMemberSummaryWriter( - AnnotationTypeWriter annotationTypeWriter, VisibleMemberMap.Kind memberType); + AnnotationTypeWriter annotationTypeWriter, VisibleMemberTable.Kind memberType); /** * Return the writer for the serialized form. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AbstractMemberBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AbstractMemberBuilder.java index 55507e09dcd..d1c7cbb7d85 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AbstractMemberBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AbstractMemberBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,14 @@ package jdk.javadoc.internal.doclets.toolkit.builders; +import java.util.List; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind; /** * The superclass for all member builders. Member builders are only executed @@ -42,13 +48,19 @@ import jdk.javadoc.internal.doclets.toolkit.DocletException; */ public abstract class AbstractMemberBuilder extends AbstractBuilder { + final protected TypeElement typeElement; + + final protected VisibleMemberTable visibleMemberTable; + /** * Construct a SubBuilder. * @param context a context object, providing information used in this run * of the doclet. */ - public AbstractMemberBuilder(Context context) { + public AbstractMemberBuilder(Context context, TypeElement typeElement) { super(context); + this.typeElement = typeElement; + visibleMemberTable = configuration.getVisibleMemberTable(typeElement); } /** @@ -77,4 +89,14 @@ public abstract class AbstractMemberBuilder extends AbstractBuilder { * @return true if this subbuilder has anything to document */ public abstract boolean hasMembersToDocument(); + + /** + * Returns a list of visible elements of the specified kind in this + * type element. + * @param kind of members + * @return a list of members + */ + protected List getVisibleMembers(Kind kind) { + return visibleMemberTable.getVisibleMembers(kind); + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeFieldBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeFieldBuilder.java index 361de387e00..8e69ca00b0c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeFieldBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeFieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; /** @@ -49,16 +49,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; */ public class AnnotationTypeFieldBuilder extends AbstractMemberBuilder { - /** - * The annotation type whose members are being documented. - */ - protected TypeElement typeElement; - - /** - * The visible members for the given class. - */ - protected VisibleMemberMap visibleMemberMap; - /** * The writer to output the member documentation. */ @@ -67,7 +57,7 @@ public class AnnotationTypeFieldBuilder extends AbstractMemberBuilder { /** * The list of members being documented. */ - protected List members; + protected List members; /** * The index of the current member that is being documented at this point @@ -86,12 +76,10 @@ public class AnnotationTypeFieldBuilder extends AbstractMemberBuilder { protected AnnotationTypeFieldBuilder(Context context, TypeElement typeElement, AnnotationTypeFieldWriter writer, - VisibleMemberMap.Kind memberType) { - super(context); - this.typeElement = typeElement; + VisibleMemberTable.Kind memberType) { + super(context, typeElement); this.writer = writer; - this.visibleMemberMap = configuration.getVisibleMemberMap(typeElement, memberType); - this.members = this.visibleMemberMap.getMembers(typeElement); + this.members = getVisibleMembers(memberType); } @@ -107,7 +95,7 @@ public class AnnotationTypeFieldBuilder extends AbstractMemberBuilder { Context context, TypeElement typeElement, AnnotationTypeFieldWriter writer) { return new AnnotationTypeFieldBuilder(context, typeElement, - writer, VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS); + writer, VisibleMemberTable.Kind.ANNOTATION_TYPE_FIELDS); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeOptionalMemberBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeOptionalMemberBuilder.java index ab15d180f98..0f62a388d54 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeOptionalMemberBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeOptionalMemberBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,8 @@ import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter; import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for optional annotation type members. @@ -57,8 +57,7 @@ public class AnnotationTypeOptionalMemberBuilder extends AnnotationTypeRequiredM private AnnotationTypeOptionalMemberBuilder(Context context, TypeElement typeElement, AnnotationTypeOptionalMemberWriter writer) { - super(context, typeElement, writer, - VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL); + super(context, typeElement, writer, ANNOTATION_TYPE_MEMBER_OPTIONAL); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java index 5b134fcee9c..f87090339e1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,9 @@ import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for required annotation type members. @@ -50,15 +51,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; */ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder { - /** - * The annotation type whose members are being documented. - */ - protected TypeElement typeElement; - - /** - * The visible members for the given class. - */ - protected VisibleMemberMap visibleMemberMap; /** * The writer to output the member documentation. @@ -68,7 +60,7 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder { /** * The list of members being documented. */ - protected List members; + protected List members; /** * The index of the current member that is being documented at this point @@ -87,12 +79,10 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder { protected AnnotationTypeRequiredMemberBuilder(Context context, TypeElement typeElement, AnnotationTypeRequiredMemberWriter writer, - VisibleMemberMap.Kind memberType) { - super(context); - this.typeElement = typeElement; + VisibleMemberTable.Kind memberType) { + super(context, typeElement); this.writer = writer; - this.visibleMemberMap = configuration.getVisibleMemberMap(typeElement, memberType); - this.members = this.visibleMemberMap.getMembers(typeElement); + this.members = getVisibleMembers(memberType); } @@ -108,8 +98,7 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder { Context context, TypeElement typeElement, AnnotationTypeRequiredMemberWriter writer) { return new AnnotationTypeRequiredMemberBuilder(context, typeElement, - writer, - VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED); + writer, ANNOTATION_TYPE_MEMBER_REQUIRED); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java index b87c39abc01..c2ccb9ac1cc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstantsSummaryBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,9 @@ import javax.lang.model.element.VariableElement; import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds the Constants Summary Page. @@ -262,9 +263,8 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { * @return true if the given package has constant fields to document. */ private boolean hasConstantField (TypeElement typeElement) { - VisibleMemberMap visibleMemberMapFields = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.FIELDS); - List fields = visibleMemberMapFields.getLeafMembers(); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(typeElement); + List fields = vmt.getVisibleMembers(FIELDS); for (Element f : fields) { VariableElement field = (VariableElement)f; if (field.getConstantValue() != null) { @@ -279,7 +279,7 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { * Return true if the given package name has been printed. Also * return true if the root of this package has been printed. * - * @param pkgname the name of the package to check. + * @param pkg the name of the package to check. */ private boolean hasPrintedPackageIndex(PackageElement pkg) { for (PackageElement printedPkg : printedPackageHeaders) { @@ -297,16 +297,6 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { */ private class ConstantFieldBuilder { - /** - * The map used to get the visible variables. - */ - protected VisibleMemberMap visibleMemberMapFields = null; - - /** - * The map used to get the visible variables. - */ - protected VisibleMemberMap visibleMemberMapEnumConst = null; - /** * The typeElement that we are examining constants for. */ @@ -318,10 +308,6 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { */ public ConstantFieldBuilder(TypeElement typeElement) { this.typeElement = typeElement; - visibleMemberMapFields = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.FIELDS); - visibleMemberMapEnumConst = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.ENUM_CONSTANTS); } /** @@ -342,8 +328,10 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { * @return the set of visible constant fields for the given type. */ protected SortedSet members() { - List members = visibleMemberMapFields.getLeafMembers(); - members.addAll(visibleMemberMapEnumConst.getLeafMembers()); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(typeElement); + List members = new ArrayList<>(); + members.addAll(vmt.getVisibleMembers(FIELDS)); + members.addAll(vmt.getVisibleMembers(ENUM_CONSTANTS)); SortedSet includes = new TreeSet<>(utils.makeGeneralPurposeComparator()); for (Element element : members) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstructorBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstructorBuilder.java index 3e51e4d9ff9..73a18e3c54a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstructorBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ConstructorBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,8 @@ import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.ConstructorWriter; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for a constructor. @@ -56,16 +56,6 @@ public class ConstructorBuilder extends AbstractMemberBuilder { */ private ExecutableElement currentConstructor; - /** - * The class whose constructors are being documented. - */ - private final TypeElement typeElement; - - /** - * The visible constructors for the given class. - */ - private final VisibleMemberMap visibleMemberMap; - /** * The writer to output the constructor documentation. */ @@ -74,7 +64,7 @@ public class ConstructorBuilder extends AbstractMemberBuilder { /** * The constructors being documented. */ - private final List constructors; + private final List constructors; /** * Construct a new ConstructorBuilder. @@ -86,12 +76,9 @@ public class ConstructorBuilder extends AbstractMemberBuilder { private ConstructorBuilder(Context context, TypeElement typeElement, ConstructorWriter writer) { - super(context); - this.typeElement = typeElement; + super(context, typeElement); this.writer = writer; - visibleMemberMap = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.CONSTRUCTORS); - constructors = visibleMemberMap.getMembers(typeElement); + constructors = getVisibleMembers(CONSTRUCTORS); for (Element ctor : constructors) { if (utils.isProtected(ctor) || utils.isPrivate(ctor)) { writer.setFoundNonPubConstructor(true); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/EnumConstantBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/EnumConstantBuilder.java index 2635c5540b3..11241855a63 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/EnumConstantBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/EnumConstantBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,8 @@ import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.EnumConstantWriter; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for a enum constants. @@ -51,16 +51,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; */ public class EnumConstantBuilder extends AbstractMemberBuilder { - /** - * The class whose enum constants are being documented. - */ - private final TypeElement typeElement; - - /** - * The visible enum constantss for the given class. - */ - private final VisibleMemberMap visibleMemberMap; - /** * The writer to output the enum constants documentation. */ @@ -69,7 +59,7 @@ public class EnumConstantBuilder extends AbstractMemberBuilder { /** * The set of enum constants being documented. */ - private final List enumConstants; + private final List enumConstants; /** * The current enum constant that is being documented at this point @@ -86,12 +76,9 @@ public class EnumConstantBuilder extends AbstractMemberBuilder { */ private EnumConstantBuilder(Context context, TypeElement typeElement, EnumConstantWriter writer) { - super(context); - this.typeElement = typeElement; + super(context, typeElement); this.writer = writer; - visibleMemberMap = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.ENUM_CONSTANTS); - enumConstants = visibleMemberMap.getMembers(typeElement); + enumConstants = getVisibleMembers(ENUM_CONSTANTS); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/FieldBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/FieldBuilder.java index abcbc4bcf14..5e98252c001 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/FieldBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/FieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,8 @@ import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.FieldWriter; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for a field. @@ -51,16 +51,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; */ public class FieldBuilder extends AbstractMemberBuilder { - /** - * The class whose fields are being documented. - */ - private final TypeElement typeElement; - - /** - * The visible fields for the given class. - */ - private final VisibleMemberMap visibleMemberMap; - /** * The writer to output the field documentation. */ @@ -69,7 +59,7 @@ public class FieldBuilder extends AbstractMemberBuilder { /** * The list of fields being documented. */ - private final List fields; + private final List fields; /** * The index of the current field that is being documented at this point @@ -85,14 +75,11 @@ public class FieldBuilder extends AbstractMemberBuilder { * @param writer the doclet specific writer. */ private FieldBuilder(Context context, - TypeElement typeElement, - FieldWriter writer) { - super(context); - this.typeElement = typeElement; + TypeElement typeElement, + FieldWriter writer) { + super(context, typeElement); this.writer = writer; - visibleMemberMap = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.FIELDS); - fields = visibleMemberMap.getLeafMembers(); + fields = getVisibleMembers(FIELDS); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java index d40607164d1..c9e11c461d8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,15 @@ package jdk.javadoc.internal.doclets.toolkit.builders; import java.text.MessageFormat; import java.util.*; +import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.util.ElementFilter; +import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTree.Kind; import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter; @@ -42,9 +45,11 @@ import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; import jdk.javadoc.internal.doclets.toolkit.WriterFactory; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; import jdk.javadoc.internal.doclets.toolkit.CommentUtils; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; + /** * Builds the member summary. * There are two anonymous subtype variants of this builder, created @@ -69,12 +74,9 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { /** * The member summary writers for the given class. */ - private final EnumMap memberSummaryWriters; + private final EnumMap memberSummaryWriters; - /** - * The type being documented. - */ - protected final TypeElement typeElement; + final PropertyHelper pHelper; /** * Construct a new MemberSummaryBuilder. @@ -83,11 +85,10 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param typeElement the type element. */ private MemberSummaryBuilder(Context context, TypeElement typeElement) { - super(context); - this.typeElement = typeElement; - memberSummaryWriters = new EnumMap<>(VisibleMemberMap.Kind.class); - - comparator = utils.makeGeneralPurposeComparator(); + super(context, typeElement); + memberSummaryWriters = new EnumMap<>(VisibleMemberTable.Kind.class); + comparator = utils.makeIndexUseComparator(); + pHelper = new PropertyHelper(this); } /** @@ -113,20 +114,14 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { @Override public boolean hasMembersToDocument() { - for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.values()) { - VisibleMemberMap members = getVisibleMemberMap(kind); - if (!members.noVisibleMembers()) { - return true; - } - } - return false; + return visibleMemberTable.hasVisibleMembers(); } }; WriterFactory wf = context.configuration.getWriterFactory(); - for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.values()) { - MemberSummaryWriter msw = builder.getVisibleMemberMap(kind).noVisibleMembers() - ? null - : wf.getMemberSummaryWriter(classWriter, kind); + for (VisibleMemberTable.Kind kind : VisibleMemberTable.Kind.values()) { + MemberSummaryWriter msw = builder.getVisibleMemberTable().hasVisibleMembers(kind) + ? wf.getMemberSummaryWriter(classWriter, kind) + : null; builder.memberSummaryWriters.put(kind, msw); } return builder; @@ -157,10 +152,10 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { } }; WriterFactory wf = context.configuration.getWriterFactory(); - for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.values()) { - MemberSummaryWriter msw = builder.getVisibleMemberMap(kind).noVisibleMembers() - ? null - : wf.getMemberSummaryWriter(annotationTypeWriter, kind); + for (VisibleMemberTable.Kind kind : VisibleMemberTable.Kind.values()) { + MemberSummaryWriter msw = builder.getVisibleMemberTable().hasVisibleMembers(kind) + ? wf.getMemberSummaryWriter(annotationTypeWriter, kind) + : null; builder.memberSummaryWriters.put(kind, msw); } return builder; @@ -169,13 +164,12 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { /** * Return the specified visible member map. * - * @param kind the kind of visible member map to return. * @return the specified visible member map. * @throws ArrayIndexOutOfBoundsException when the type is invalid. - * @see VisibleMemberMap + * @see VisibleMemberTable */ - public VisibleMemberMap getVisibleMemberMap(VisibleMemberMap.Kind kind) { - return configuration.getVisibleMemberMap(typeElement, kind); + public VisibleMemberTable getVisibleMemberTable() { + return visibleMemberTable; } /**. @@ -184,9 +178,9 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param kind the kind of member summary writer to return. * @return the specified member summary writer. * @throws ArrayIndexOutOfBoundsException when the type is invalid. - * @see VisibleMemberMap + * @see VisibleMemberTable */ - public MemberSummaryWriter getMemberSummaryWriter(VisibleMemberMap.Kind kind) { + public MemberSummaryWriter getMemberSummaryWriter(VisibleMemberTable.Kind kind) { return memberSummaryWriters.get(kind); } @@ -197,25 +191,31 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * * @param kind the kind of elements to return. * @return a list of methods that will be documented. - * @see VisibleMemberMap + * @see VisibleMemberTable */ - public SortedSet members(VisibleMemberMap.Kind kind) { + public SortedSet members(VisibleMemberTable.Kind kind) { TreeSet out = new TreeSet<>(comparator); - out.addAll(getVisibleMemberMap(kind).getLeafMembers()); + out.addAll(getVisibleMembers(kind)); return out; } + /** + * Returns true if there are members of the given kind, false otherwise. + * @param kind + * @return true if there are members of the given kind, false otherwise + */ + public boolean hasMembers(VisibleMemberTable.Kind kind) { + return !getVisibleMembers(kind).isEmpty(); + } + /** * Build the summary for the enum constants. * * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildEnumConstantsSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.ENUM_CONSTANTS); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.ENUM_CONSTANTS); - addSummary(writer, visibleMemberMap, false, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(ENUM_CONSTANTS); + addSummary(writer, ENUM_CONSTANTS, false, memberSummaryTree); } /** @@ -224,11 +224,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildAnnotationTypeFieldsSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS); - addSummary(writer, visibleMemberMap, false, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(ANNOTATION_TYPE_FIELDS); + addSummary(writer, ANNOTATION_TYPE_FIELDS, false, memberSummaryTree); } /** @@ -237,11 +234,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildAnnotationTypeOptionalMemberSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL); - addSummary(writer, visibleMemberMap, false, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(ANNOTATION_TYPE_MEMBER_OPTIONAL); + addSummary(writer, ANNOTATION_TYPE_MEMBER_OPTIONAL, false, memberSummaryTree); } /** @@ -250,11 +244,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildAnnotationTypeRequiredMemberSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED); - addSummary(writer, visibleMemberMap, false, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(ANNOTATION_TYPE_MEMBER_REQUIRED); + addSummary(writer, ANNOTATION_TYPE_MEMBER_REQUIRED, false, memberSummaryTree); } /** @@ -263,11 +254,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildFieldsSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.FIELDS); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.FIELDS); - addSummary(writer, visibleMemberMap, true, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(FIELDS); + addSummary(writer, FIELDS, true, memberSummaryTree); } /** @@ -276,11 +264,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildPropertiesSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.PROPERTIES); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.PROPERTIES); - addSummary(writer, visibleMemberMap, true, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(PROPERTIES); + addSummary(writer, PROPERTIES, true, memberSummaryTree); } /** @@ -289,11 +274,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildNestedClassesSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.INNER_CLASSES); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.INNER_CLASSES); - addSummary(writer, visibleMemberMap, true, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(INNER_CLASSES); + addSummary(writer, INNER_CLASSES, true, memberSummaryTree); } /** @@ -302,11 +284,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildMethodsSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.METHODS); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.METHODS); - addSummary(writer, visibleMemberMap, true, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(METHODS); + addSummary(writer, METHODS, true, memberSummaryTree); } /** @@ -315,28 +294,25 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * @param memberSummaryTree the content tree to which the documentation will be added */ protected void buildConstructorsSummary(Content memberSummaryTree) { - MemberSummaryWriter writer = - memberSummaryWriters.get(VisibleMemberMap.Kind.CONSTRUCTORS); - VisibleMemberMap visibleMemberMap = - getVisibleMemberMap(VisibleMemberMap.Kind.CONSTRUCTORS); - addSummary(writer, visibleMemberMap, false, memberSummaryTree); + MemberSummaryWriter writer = memberSummaryWriters.get(CONSTRUCTORS); + addSummary(writer, CONSTRUCTORS, false, memberSummaryTree); } /** * Build the member summary for the given members. * * @param writer the summary writer to write the output. - * @param visibleMemberMap the given members to summarize. + * @param kind the kind of members to summarize. * @param summaryTreeList list of content trees to which the documentation will be added */ private void buildSummary(MemberSummaryWriter writer, - VisibleMemberMap visibleMemberMap, LinkedList summaryTreeList) { - SortedSet members = asSortedSet(visibleMemberMap.getLeafMembers()); + VisibleMemberTable.Kind kind, LinkedList summaryTreeList) { + SortedSet members = asSortedSet(getVisibleMembers(kind)); if (!members.isEmpty()) { for (Element member : members) { - final Element property = visibleMemberMap.getPropertyElement(member); + final Element property = pHelper.getPropertyElement(member); if (property != null) { - processProperty(visibleMemberMap, member, property); + processProperty(member, property); } List firstSentenceTags = utils.getFirstSentenceTrees(member); if (utils.isExecutableElement(member) && firstSentenceTags.isEmpty()) { @@ -367,12 +343,10 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * the see tags if the appropriate property getter and setter are * available. * - * @param visibleMemberMap the members information. * @param member the member which is to be augmented. * @param property the original property documentation. */ - private void processProperty(VisibleMemberMap visibleMemberMap, - Element member, + private void processProperty(Element member, Element property) { CommentUtils cmtutils = configuration.cmtUtils; final boolean isSetter = isSetter(member); @@ -418,8 +392,8 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { //add @see tags if (!isGetter && !isSetter) { - ExecutableElement getter = (ExecutableElement) visibleMemberMap.getGetterForProperty(member); - ExecutableElement setter = (ExecutableElement) visibleMemberMap.getSetterForProperty(member); + ExecutableElement getter = pHelper.getGetterForProperty((ExecutableElement)member); + ExecutableElement setter = pHelper.getSetterForProperty((ExecutableElement)member); if (null != getter) { StringBuilder sb = new StringBuilder("#"); @@ -465,47 +439,28 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * Build the inherited member summary for the given methods. * * @param writer the writer for this member summary. - * @param visibleMemberMap the map for the members to document. + * @param kind the kind of members to document. * @param summaryTreeList list of content trees to which the documentation will be added */ private void buildInheritedSummary(MemberSummaryWriter writer, - VisibleMemberMap visibleMemberMap, LinkedList summaryTreeList) { - for (TypeElement inheritedClass : visibleMemberMap.getVisibleClasses()) { + VisibleMemberTable.Kind kind, LinkedList summaryTreeList) { + VisibleMemberTable visibleMemberTable = getVisibleMemberTable(); + SortedSet inheritedMembersFromMap = asSortedSet(visibleMemberTable.getAllVisibleMembers(kind)); + + for (TypeElement inheritedClass : visibleMemberTable.getVisibleTypeElements()) { if (!(utils.isPublic(inheritedClass) || utils.isLinkable(inheritedClass))) { continue; } if (inheritedClass == typeElement) { continue; } - SortedSet inheritedMembersFromMap = asSortedSet( - visibleMemberMap.getMembers(inheritedClass)); - if (!inheritedMembersFromMap.isEmpty()) { + List members = inheritedMembersFromMap.stream() + .filter(e -> utils.getEnclosingTypeElement(e) == inheritedClass) + .collect(Collectors.toList()); + if (!members.isEmpty()) { SortedSet inheritedMembers = new TreeSet<>(comparator); - List enclosedSuperMethods = utils.getMethods(inheritedClass); - for (Element inheritedMember : inheritedMembersFromMap) { - if (visibleMemberMap.kind != VisibleMemberMap.Kind.METHODS) { - inheritedMembers.add(inheritedMember); - continue; - } - - // Skip static methods in interfaces they are not inherited - if (utils.isInterface(inheritedClass) && utils.isStatic(inheritedMember)) - continue; - - // If applicable, filter those overridden methods that - // should not be documented in the summary/detail sections, - // and instead document them in the footnote. Care must be taken - // to handle JavaFX property methods, which have no source comments, - // but comments for these are synthesized on the output. - ExecutableElement inheritedMethod = (ExecutableElement)inheritedMember; - if (enclosedSuperMethods.stream() - .anyMatch(e -> utils.executableMembersEqual(inheritedMethod, e) && - (!utils.isSimpleOverride(e) || visibleMemberMap.getPropertyElement(e) != null))) { - inheritedMembers.add(inheritedMember); - } - } - + inheritedMembers.addAll(members); Content inheritedTree = writer.getInheritedSummaryHeader(inheritedClass); Content linksTree = writer.getInheritedSummaryLinksTree(); addSummaryFootNote(inheritedClass, inheritedMembers, linksTree, writer); @@ -529,17 +484,17 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { * Add the summary for the documentation. * * @param writer the writer for this member summary. - * @param visibleMemberMap the map for the members to document. + * @param kind the kind of members to document. * @param showInheritedSummary true if inherited summary should be documented * @param memberSummaryTree the content tree to which the documentation will be added */ private void addSummary(MemberSummaryWriter writer, - VisibleMemberMap visibleMemberMap, boolean showInheritedSummary, + VisibleMemberTable.Kind kind, boolean showInheritedSummary, Content memberSummaryTree) { LinkedList summaryTreeList = new LinkedList<>(); - buildSummary(writer, visibleMemberMap, summaryTreeList); + buildSummary(writer, kind, summaryTreeList); if (showInheritedSummary) - buildInheritedSummary(writer, visibleMemberMap, summaryTreeList); + buildInheritedSummary(writer, kind, summaryTreeList); if (!summaryTreeList.isEmpty()) { Content memberTree = writer.getMemberSummaryHeader(typeElement, memberSummaryTree); summaryTreeList.stream().forEach(memberTree::addContent); @@ -547,9 +502,91 @@ public abstract class MemberSummaryBuilder extends AbstractMemberBuilder { } } - private SortedSet asSortedSet(Collection members) { + private SortedSet asSortedSet(Collection members) { SortedSet out = new TreeSet<>(comparator); out.addAll(members); return out; } + + static class PropertyHelper { + + private final Map classPropertiesMap = new HashMap<>(); + + private final MemberSummaryBuilder builder; + + PropertyHelper(MemberSummaryBuilder builder) { + this.builder = builder; + computeProperties(); + } + + private void computeProperties() { + VisibleMemberTable vmt = builder.getVisibleMemberTable(); + List props = ElementFilter.methodsIn(vmt.getVisibleMembers(PROPERTIES)); + for (ExecutableElement propertyMethod : props) { + ExecutableElement getter = vmt.getPropertyGetter(propertyMethod); + ExecutableElement setter = vmt.getPropertySetter(propertyMethod); + VariableElement field = vmt.getPropertyField(propertyMethod); + + addToPropertiesMap(propertyMethod, field, getter, setter); + } + } + + private void addToPropertiesMap(ExecutableElement propertyMethod, + VariableElement field, + ExecutableElement getter, + ExecutableElement setter) { + if (field == null || builder.utils.getDocCommentTree(field) == null) { + addToPropertiesMap(propertyMethod, propertyMethod); + addToPropertiesMap(getter, propertyMethod); + addToPropertiesMap(setter, propertyMethod); + } else { + addToPropertiesMap(propertyMethod, field); + addToPropertiesMap(getter, field); + addToPropertiesMap(setter, field); + } + } + + private void addToPropertiesMap(Element propertyMethod, + Element commentSource) { + if (null == propertyMethod || null == commentSource) { + return; + } + DocCommentTree docTree = builder.utils.getDocCommentTree(propertyMethod); + + /* The second condition is required for the property buckets. In + * this case the comment is at the property method (not at the field) + * and it needs to be listed in the map. + */ + if ((docTree == null) || propertyMethod.equals(commentSource)) { + classPropertiesMap.put(propertyMethod, commentSource); + } + } + + /** + * Returns the property field documentation belonging to the given member. + * @param element the member for which the property documentation is needed. + * @return the property field documentation, null if there is none. + */ + public Element getPropertyElement(Element element) { + return classPropertiesMap.get(element); + } + + /** + * Returns the getter documentation belonging to the given property method. + * @param propertyMethod the method for which the getter is needed. + * @return the getter documentation, null if there is none. + */ + public ExecutableElement getGetterForProperty(ExecutableElement propertyMethod) { + return builder.getVisibleMemberTable().getPropertyGetter(propertyMethod); + } + + /** + * Returns the setter documentation belonging to the given property method. + * @param propertyMethod the method for which the setter is needed. + * @return the setter documentation, null if there is none. + */ + public ExecutableElement getSetterForProperty(ExecutableElement propertyMethod) { + return builder.getVisibleMemberTable().getPropertySetter(propertyMethod); + } + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java index 1c1e0942340..0f72dd671f7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,8 @@ import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.MethodWriter; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for a method. @@ -59,16 +59,6 @@ public class MethodBuilder extends AbstractMemberBuilder { */ private ExecutableElement currentMethod; - /** - * The class whose methods are being documented. - */ - private final TypeElement typeElement; - - /** - * The visible methods for the given class. - */ - private final VisibleMemberMap visibleMemberMap; - /** * The writer to output the method documentation. */ @@ -77,7 +67,7 @@ public class MethodBuilder extends AbstractMemberBuilder { /** * The methods being documented. */ - private final List methods; + private final List methods; /** @@ -90,12 +80,9 @@ public class MethodBuilder extends AbstractMemberBuilder { private MethodBuilder(Context context, TypeElement typeElement, MethodWriter writer) { - super(context); - this.typeElement = typeElement; + super(context, typeElement); this.writer = writer; - visibleMemberMap = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.METHODS); - methods = visibleMemberMap.getLeafMembers(); + methods = getVisibleMembers(METHODS); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java index e678aa0d3d6..4cc106b9517 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PropertyBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,9 @@ import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.PropertyWriter; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; +import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Builds documentation for a property. @@ -51,16 +52,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; */ public class PropertyBuilder extends AbstractMemberBuilder { - /** - * The class whose properties are being documented. - */ - private final TypeElement typeElement; - - /** - * The visible properties for the given class. - */ - private final VisibleMemberMap visibleMemberMap; - /** * The writer to output the property documentation. */ @@ -69,7 +60,7 @@ public class PropertyBuilder extends AbstractMemberBuilder { /** * The list of properties being documented. */ - private final List properties; + private final List properties; /** * The index of the current property that is being documented at this point @@ -87,12 +78,9 @@ public class PropertyBuilder extends AbstractMemberBuilder { private PropertyBuilder(Context context, TypeElement typeElement, PropertyWriter writer) { - super(context); - this.typeElement = typeElement; + super(context, typeElement); this.writer = writer; - visibleMemberMap = configuration.getVisibleMemberMap(typeElement, - VisibleMemberMap.Kind.PROPERTIES); - properties = visibleMemberMap.getMembers(typeElement); + properties = getVisibleMembers(PROPERTIES); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 24b94dff5f2..f426a27d2d4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -84,7 +84,6 @@ doclet.UnknownTagLowercase={0} is an unknown tag -- same as a known tag except f doclet.noInheritedDoc=@inheritDoc used but {0} does not override or implement any method. # doclet.malformed_html_link_tag= tag is malformed:\n"{0}" doclet.tag_misuse=Tag {0} cannot be used in {1} documentation. It can only be used in the following types of documentation: {2}. -doclet.javafx_tag_misuse=Tags @propertyGetter, @propertySetter and @propertyDescription can only be used in JavaFX properties getters and setters. doclet.Package_Summary=Package Summary doclet.Requires_Summary=Requires doclet.Indirect_Requires_Summary=Indirect Requires diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties index 3b02124e1c7..ec93c8f30c4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties @@ -75,7 +75,6 @@ doclet.UnknownTagLowercase={0}\u306F\u4E0D\u660E\u306A\u30BF\u30B0\u3067\u3059\u doclet.noInheritedDoc=@inheritDoc\u304C\u4F7F\u7528\u3055\u308C\u3066\u3044\u307E\u3059\u304C\u3001{0}\u306F\u3069\u306E\u30E1\u30BD\u30C3\u30C9\u3082\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u307E\u305F\u306F\u5B9F\u88C5\u3057\u3066\u3044\u307E\u305B\u3093\u3002 # doclet.malformed_html_link_tag= tag is malformed:\n"{0}" doclet.tag_misuse={0}\u30BF\u30B0\u306F{1}\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u5185\u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u4F7F\u7528\u3067\u304D\u308B\u306E\u306F\u6B21\u306E\u30BF\u30A4\u30D7\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u5185\u306E\u307F\u3067\u3059: {2}\u3002 -doclet.javafx_tag_misuse=\u30BF\u30B0@propertyGetter\u3001@propertySetter\u304A\u3088\u3073@propertyDescription\u306F\u3001JavaFX\u306E\u30D7\u30ED\u30D1\u30C6\u30A3getter\u3068setter\u306E\u307F\u3067\u4F7F\u7528\u3067\u304D\u307E\u3059\u3002 doclet.Package_Summary=\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u6982\u8981 doclet.Requires_Summary=\u5FC5\u8981 doclet.Indirect_Requires_Summary=\u9593\u63A5\u7684\u306B\u5FC5\u8981 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties index 98abaa75f21..c3f543db8a9 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties @@ -75,7 +75,6 @@ doclet.UnknownTagLowercase={0}\u662F\u672A\u77E5\u6807\u8BB0 - \u9664\u4E86\u592 doclet.noInheritedDoc=\u4F7F\u7528\u4E86 @inheritDoc, \u4F46{0}\u672A\u8986\u76D6\u6216\u5B9E\u73B0\u4EFB\u4F55\u65B9\u6CD5\u3002 # doclet.malformed_html_link_tag= tag is malformed:\n"{0}" doclet.tag_misuse=\u4E0D\u80FD\u5728{1}\u6587\u6863\u4E2D\u4F7F\u7528\u6807\u8BB0{0}\u3002\u53EA\u80FD\u5728\u4EE5\u4E0B\u7C7B\u578B\u7684\u6587\u6863\u4E2D\u4F7F\u7528\u8BE5\u6807\u8BB0: {2}\u3002 -doclet.javafx_tag_misuse=\u6807\u8BB0 @propertyGetter, @propertySetter \u548C @propertyDescription \u53EA\u80FD\u5728 JavaFX \u5C5E\u6027 getter \u548C setter \u4E2D\u4F7F\u7528\u3002 doclet.Package_Summary=\u7A0B\u5E8F\u5305\u6982\u8981 doclet.Requires_Summary=\u5FC5\u9700\u9879 doclet.Indirect_Requires_Summary=\u95F4\u63A5\u5FC5\u9700\u9879 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java index 8a975367477..c9ef88db339 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package jdk.javadoc.internal.doclets.toolkit.taglets; import java.io.*; -import java.lang.reflect.InvocationTargetException; import java.util.*; import javax.lang.model.element.Element; @@ -180,8 +179,7 @@ public class TagletManager { private final boolean showauthor; /** - * True if we want to use JavaFX-related tags (@propertyGetter, - * @propertySetter, @propertyDescription, @defaultValue, @treatAsPrivate). + * True if we want to use JavaFX-related tags (@defaultValue, @treatAsPrivate). */ private final boolean javafx; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java index f47d0e073b7..9a1a54906cd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,7 +161,6 @@ public class ClassTree { * have their own sub-class lists. * * @param classes all the classes in this run. - * @param configuration the current configuration of the doclet. */ private void buildTree(Iterable classes) { for (TypeElement aClass : classes) { @@ -174,7 +173,7 @@ public class ClassTree { continue; } - if (utils.isHidden(aClass)) { + if (utils.hasHiddenTag(aClass)) { continue; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java index a1929b6d4c0..7f17ff52bfd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java @@ -47,7 +47,8 @@ import javax.lang.model.util.Types; import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind; + +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Map all class uses for a given class. @@ -243,8 +244,9 @@ public class ClassUseMapper { mapExecutable(ctor); } - VisibleMemberMap vmm = configuration.getVisibleMemberMap(aClass, Kind.METHODS); - List methods = ElementFilter.methodsIn(vmm.getMembers(aClass)); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(aClass); + List methods = ElementFilter.methodsIn(vmt.getMembers(METHODS)); + for (ExecutableElement method : methods) { mapExecutable(method); mapTypeParameters(classToMethodTypeParam, method, method); @@ -554,8 +556,8 @@ public class ClassUseMapper { * Map the AnnotationType to the members that use them as type parameters. * * @param map the map the insert the information into. - * @param element whose type parameters are being checked. - * @param holder the holder that owns the type parameters. + * @param e whose type parameters are being checked. + * @param holder owning the type parameters. */ private void mapAnnotations(final Map> map, Element e, final T holder) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFinder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFinder.java index 449e8013e08..bd854fbc125 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFinder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -276,9 +276,10 @@ public class DocFinder { //NOTE: When we fix the bug where ClassDoc.interfaceTypes() does // not pass all implemented interfaces, we will use the // appropriate element here. - ImplementedMethods implMethods - = new ImplementedMethods((ExecutableElement) input.element, configuration); - List implementedMethods = implMethods.build(); + TypeElement encl = utils.getEnclosingTypeElement(input.element); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(encl); + List implementedMethods = + vmt.getImplementedMethods((ExecutableElement)input.element); for (ExecutableElement implementedMethod : implementedMethods) { inheritedSearchInput.element = implementedMethod; output = search(configuration, inheritedSearchInput); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ImplementedMethods.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ImplementedMethods.java deleted file mode 100644 index 9628bb3a07f..00000000000 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ImplementedMethods.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.javadoc.internal.doclets.toolkit.util; - -import java.util.*; - -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeMirror; - -import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; - -/** - * For a given class method, build an array of interface methods which it - * implements. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - * - * @author Atul M Dambalkar - */ -public class ImplementedMethods { - - private final Map interfaces = new HashMap<>(); - private final List methlist = new ArrayList<>(); - private final Utils utils; - private final TypeElement typeElement; - private final ExecutableElement method; - - public ImplementedMethods(ExecutableElement method, BaseConfiguration configuration) { - this.method = method; - this.utils = configuration.utils; - typeElement = utils.getEnclosingTypeElement(method); - } - - /** - * Return the array of interface methods which the method passed in the - * constructor is implementing. The search/build order is as follows: - *

-     * 1. Search in all the immediate interfaces which this method's class is
-     *    implementing. Do it recursively for the superinterfaces as well.
-     * 2. Traverse all the superclasses and search recursively in the
-     *    interfaces which those superclasses implement.
-     *
- * - * @return SortedSet of implemented methods. - */ - public List build() { - buildImplementedMethodList(); - return methlist; - } - - public TypeMirror getMethodHolder(ExecutableElement ee) { - return interfaces.get(ee); - } - - /** - * Search for the method in the array of interfaces. If found check if it is - * overridden by any other subinterface method which this class - * implements. If it is not overidden, add it in the method list. - * Do this recursively for all the extended interfaces for each interface - * from the array passed. - */ - private void buildImplementedMethodList() { - Set intfacs = utils.getAllInterfaces(typeElement); - for (TypeMirror interfaceType : intfacs) { - ExecutableElement found = utils.findMethod(utils.asTypeElement(interfaceType), method); - if (found != null) { - removeOverriddenMethod(found); - if (!overridingMethodFound(found)) { - methlist.add(found); - interfaces.put(found, interfaceType); - } - } - } - } - - /** - * Search in the method list and check if it contains a method which - * is overridden by the method as parameter. If found, remove the - * overridden method from the method list. - * - * @param method Is this method overriding a method in the method list. - */ - private void removeOverriddenMethod(ExecutableElement method) { - TypeElement overriddenClass = utils.overriddenClass(method); - if (overriddenClass != null) { - for (int i = 0; i < methlist.size(); i++) { - TypeElement te = utils.getEnclosingTypeElement(methlist.get(i)); - if (te == overriddenClass || utils.isSubclassOf(overriddenClass, te)) { - methlist.remove(i); // remove overridden method - return; - } - } - } - } - - /** - * Search in the already found methods' list and check if it contains - * a method which is overriding the method parameter or is the method - * parameter itself. - * - * @param method MethodDoc Method to be searched in the Method List for - * an overriding method. - */ - private boolean overridingMethodFound(ExecutableElement method) { - TypeElement containingClass = utils.getEnclosingTypeElement(method); - for (ExecutableElement listmethod : methlist) { - if (containingClass == utils.getEnclosingTypeElement(listmethod)) { - // it's the same method. - return true; - } - TypeElement te = utils.overriddenClass(listmethod); - if (te == null) { - continue; - } - if (te == containingClass || utils.isSubclassOf(te, containingClass)) { - return true; - } - } - return false; - } -} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java index c361d31eae5..150ed90ea71 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,8 @@ import javax.lang.model.element.TypeElement; import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Messages; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind; + +import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*; /** * Build the mapping of each Unicode character with it's member lists @@ -165,8 +166,8 @@ public class IndexBuilder { protected void putMembersInIndexMap(TypeElement te) { adjustIndexMap(utils.getAnnotationFields(te)); adjustIndexMap(utils.getFields(te)); - VisibleMemberMap vmm = configuration.getVisibleMemberMap(te, Kind.METHODS); - adjustIndexMap(vmm.getMembers(te)); + VisibleMemberTable vmt = configuration.getVisibleMemberTable(te); + adjustIndexMap(vmt.getMembers(METHODS)); adjustIndexMap(utils.getConstructors(te)); adjustIndexMap(utils.getEnumConstants(te)); } @@ -216,7 +217,7 @@ public class IndexBuilder { * Should this element be added to the index map? */ protected boolean shouldAddToIndexMap(Element element) { - if (utils.isHidden(element)) { + if (utils.hasHiddenTag(element)) { return false; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 61c4de3b03c..55f62e6b771 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -74,12 +74,10 @@ import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTree.Kind; import com.sun.source.doctree.ParamTree; import com.sun.source.doctree.SerialFieldTree; -import com.sun.source.doctree.StartElementTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.LineMap; import com.sun.source.util.DocSourcePositions; import com.sun.source.util.DocTrees; -import com.sun.source.util.SimpleDocTreeVisitor; import com.sun.source.util.TreePath; import com.sun.tools.javac.model.JavacTypes; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; @@ -95,7 +93,6 @@ import static javax.lang.model.type.TypeKind.*; import static com.sun.source.doctree.DocTree.Kind.*; import static jdk.javadoc.internal.doclets.toolkit.builders.ConstantsSummaryBuilder.MAX_CONSTANT_VALUE_INDEX_LENGTH; - /** * Utilities Class for Doclets. * @@ -806,9 +803,8 @@ public class Utils { if (te == null) { return null; } - VisibleMemberMap vmm = configuration.getVisibleMemberMap(te, - VisibleMemberMap.Kind.METHODS); - for (Element e : vmm.getMembers(te)) { + VisibleMemberTable vmt = configuration.getVisibleMemberTable(te); + for (Element e : vmt.getMembers(VisibleMemberTable.Kind.METHODS)) { ExecutableElement ee = (ExecutableElement)e; if (configuration.workArounds.overrides(method, ee, origin) && !isSimpleOverride(ee)) { @@ -1167,7 +1163,7 @@ public class Utils { } TypeElement superClass = asTypeElement(superType); // skip "hidden" classes - while ((superClass != null && isHidden(superClass)) + while ((superClass != null && hasHiddenTag(superClass)) || (superClass != null && !isPublic(superClass) && !isLinkable(superClass))) { TypeMirror supersuperType = superClass.getSuperclass(); TypeElement supersuperClass = asTypeElement(supersuperType); @@ -1416,7 +1412,7 @@ public class Utils { * @param e the queried element * @return true if it exists, false otherwise */ - public boolean isHidden(Element e) { + public boolean hasHiddenTag(Element e) { // prevent needless tests on elements which are not included if (!isIncluded(e)) { return false; @@ -1462,14 +1458,14 @@ public class Utils { new TreeSet<>(makeGeneralPurposeComparator()); if (!javafx) { for (Element te : classlist) { - if (!isHidden(te)) { + if (!hasHiddenTag(te)) { filteredOutClasses.add((TypeElement)te); } } return filteredOutClasses; } for (Element e : classlist) { - if (isPrivate(e) || isPackagePrivate(e) || isHidden(e)) { + if (isPrivate(e) || isPackagePrivate(e) || hasHiddenTag(e)) { continue; } filteredOutClasses.add((TypeElement)e); @@ -2246,18 +2242,6 @@ public class Utils { return convertToTypeElement(getItems(e, false, INTERFACE)); } - List getNestedClasses(TypeElement e) { - List result = new ArrayList<>(); - recursiveGetItems(result, e, true, CLASS); - return result; - } - - List getNestedClassesUnfiltered(TypeElement e) { - List result = new ArrayList<>(); - recursiveGetItems(result, e, false, CLASS); - return result; - } - public List getEnumConstants(Element e) { return getItems(e, true, ENUM_CONSTANT); } @@ -2381,7 +2365,6 @@ public class Utils { } EnumSet nestedKinds = EnumSet.of(ANNOTATION_TYPE, CLASS, ENUM, INTERFACE); - void recursiveGetItems(Collection list, Element e, boolean filter, ElementKind... select) { list.addAll(getItems0(e, filter, select)); List classes = getItems0(e, filter, nestedKinds); @@ -2411,7 +2394,8 @@ public class Utils { } private SimpleElementVisitor9 shouldDocumentVisitor = null; - private boolean shouldDocument(Element e) { + + protected boolean shouldDocument(Element e) { if (shouldDocumentVisitor == null) { shouldDocumentVisitor = new SimpleElementVisitor9() { private boolean hasSource(TypeElement e) { @@ -2422,6 +2406,10 @@ public class Utils { // handle types @Override public Boolean visitType(TypeElement e, Void p) { + // treat inner classes etc as members + if (e.getNestingKind().isNested()) { + return defaultAction(e, p); + } return configuration.docEnv.isSelected(e) && hasSource(e); } @@ -3273,5 +3261,11 @@ public class Utils { this.first = first; this.second = second; } + + public String toString() { + StringBuffer out = new StringBuffer(); + out.append(first + ":" + second); + return out.toString(); + } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberCache.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberCache.java new file mode 100644 index 00000000000..f85674bed89 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberCache.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.toolkit.util; + +import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * This class manages the visible member table for each type element. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ + +public class VisibleMemberCache { + private final Map cache; + private final BaseConfiguration configuration; + + public VisibleMemberCache(BaseConfiguration configuration) { + this.configuration = configuration; + cache = new HashMap<>(); + } + + public VisibleMemberTable getVisibleMemberTable(TypeElement te) { + return cache.computeIfAbsent(te, t -> new VisibleMemberTable(t, configuration, this)); + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java deleted file mode 100644 index 0a362e22952..00000000000 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java +++ /dev/null @@ -1,842 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.javadoc.internal.doclets.toolkit.util; - -import java.util.*; -import java.util.regex.Pattern; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; - -import com.sun.source.doctree.DocCommentTree; -import com.sun.source.doctree.DocTree; - -import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; -import jdk.javadoc.internal.doclets.toolkit.Messages; - -/** - * A data structure that encapsulates the visible members of a particular - * type for a given class tree. To use this data structure, you must specify - * the type of member you are interested in (nested class, field, constructor - * or method) and the leaf of the class tree. The data structure will map - * all visible members in the leaf and classes above the leaf in the tree. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - * - * @author Atul M Dambalkar - * @author Jamie Ho (rewrite) - */ -public class VisibleMemberMap { - - private boolean noVisibleMembers = true; - - public static enum Kind { - INNER_CLASSES, - ENUM_CONSTANTS, - FIELDS, - CONSTRUCTORS, - METHODS, - ANNOTATION_TYPE_FIELDS, - ANNOTATION_TYPE_MEMBER_OPTIONAL, - ANNOTATION_TYPE_MEMBER_REQUIRED, - PROPERTIES; - - public static final EnumSet summarySet = EnumSet.range(INNER_CLASSES, METHODS); - public static final EnumSet detailSet = EnumSet.range(ENUM_CONSTANTS, METHODS); - public static String getNavLinkLabels(Kind kind) { - switch (kind) { - case INNER_CLASSES: - return "doclet.navNested"; - case ENUM_CONSTANTS: - return "doclet.navEnum"; - case FIELDS: - return "doclet.navField"; - case CONSTRUCTORS: - return "doclet.navConstructor"; - case METHODS: - return "doclet.navMethod"; - default: - throw new AssertionError("unknown kind:" + kind); - } - } - } - - public static final String STARTLEVEL = "start"; - - // properties aren't named setA* or getA* - private static final Pattern GETTERSETTERPATTERN = Pattern.compile("[sg]et\\p{Upper}.*"); - /** - * List of TypeElement objects for which ClassMembers objects are built. - */ - private final Set visibleClasses; - - /** - * Map for each member name on to a map which contains members with same - * name-signature. The mapped map will contain mapping for each MemberDoc - * onto it's respecive level string. - */ - private final Map> memberNameMap = new HashMap<>(); - - /** - * Map of class and it's ClassMembers object. - */ - private final Map classMap = new HashMap<>(); - - /** - * Type whose visible members are requested. This is the leaf of - * the class tree being mapped. - */ - private final TypeElement typeElement; - - /** - * Member kind: InnerClasses/Fields/Methods? - */ - public final Kind kind; - - /** - * The configuration this VisibleMemberMap was created with. - */ - private final BaseConfiguration configuration; - private final Messages messages; - private final Utils utils; - private final Comparator comparator; - - private final Map> propertiesCache; - private final Map classPropertiesMap; - private final Map getterSetterMap; - - /** - * Construct a VisibleMemberMap of the given type for the given class. - * - * @param typeElement whose members are being mapped. - * @param kind the kind of member that is being mapped. - * @param configuration the configuration to use to construct this - * VisibleMemberMap. If the field configuration.nodeprecated is true the - * deprecated members are excluded from the map. If the field - * configuration.javafx is true the JavaFX features are used. - */ - public VisibleMemberMap(TypeElement typeElement, - Kind kind, - BaseConfiguration configuration) { - this.typeElement = typeElement; - this.kind = kind; - this.configuration = configuration; - this.messages = configuration.getMessages(); - this.utils = configuration.utils; - propertiesCache = configuration.propertiesCache; - classPropertiesMap = configuration.classPropertiesMap; - getterSetterMap = configuration.getterSetterMap; - comparator = utils.makeGeneralPurposeComparator(); - visibleClasses = new LinkedHashSet<>(); - new ClassMembers(typeElement, STARTLEVEL).build(); - } - - /** - * Return the list of visible classes in this map. - * - * @return the list of visible classes in this map. - */ - public SortedSet getVisibleClasses() { - SortedSet vClasses = new TreeSet<>(comparator); - vClasses.addAll(visibleClasses); - return vClasses; - } - - /** - * Returns the first method where the given method is visible. - * @param e the method whose visible enclosing type is to be found. - * @return the method found or null - */ - public ExecutableElement getVisibleMethod(ExecutableElement e) { - if (kind != Kind.METHODS || e.getKind() != ElementKind.METHOD) { - throw new AssertionError("incompatible member type or visible member map" + e); - } - // start with the current class - for (Element m : getMembers(typeElement)) { - ExecutableElement mthd = (ExecutableElement)m; - if (utils.executableMembersEqual(mthd, e)) { - return mthd; - } - } - - for (TypeElement te : visibleClasses) { - if (te == typeElement) - continue; - for (Element m : getMembers(te)) { - ExecutableElement mthd = (ExecutableElement)m; - if (utils.executableMembersEqual(mthd, e)) { - return mthd; - } - } - } - return null; - } - - /** - * Returns the property field documentation belonging to the given member. - * @param element the member for which the property documentation is needed. - * @return the property field documentation, null if there is none. - */ - public Element getPropertyElement(Element element) { - return classPropertiesMap.get(element); - } - - /** - * Returns the getter documentation belonging to the given property method. - * @param propertyMethod the method for which the getter is needed. - * @return the getter documentation, null if there is none. - */ - public Element getGetterForProperty(Element propertyMethod) { - return getterSetterMap.get(propertyMethod).getGetter(); - } - - /** - * Returns the setter documentation belonging to the given property method. - * @param propertyMethod the method for which the setter is needed. - * @return the setter documentation, null if there is none. - */ - public Element getSetterForProperty(Element propertyMethod) { - return getterSetterMap.get(propertyMethod).getSetter(); - } - - /** - * Return the package private members inherited by the class. Only return - * if parent is package private and not documented. - * - * @return the package private members inherited by the class. - */ - private List getInheritedPackagePrivateMethods() { - List results = new ArrayList<>(); - for (TypeElement currentClass : visibleClasses) { - if (currentClass != typeElement && - utils.isPackagePrivate(currentClass) && - !utils.isLinkable(currentClass)) { - // Document these members in the child class because - // the parent is inaccessible. - results.addAll(classMap.get(currentClass).members); - } - } - return results; - } - - /** - * Returns a list of visible enclosed members of the mapped type element. - * - * In the case of methods, the list may contain those methods that are - * extended with no specification changes as indicated by the existence - * of a sole @inheritDoc or devoid of any API commments. - * - * This list may also contain appended members, inherited by inaccessible - * super types. These members are documented in the subtype when the - * super type is not documented. - * - * @return a list of visible enclosed members - */ - - public List getLeafMembers() { - List result = new ArrayList<>(); - result.addAll(getMembers(typeElement)); - result.addAll(getInheritedPackagePrivateMethods()); - return result; - } - - // Cache to improve performance - private HashMap overridenMethodCache = new HashMap<>(); - - private boolean hasOverridden(ExecutableElement method) { - return overridenMethodCache.computeIfAbsent(method, m -> hasOverriddenCompute(m)); - } - - private boolean hasOverriddenCompute(ExecutableElement method) { - if (kind != Kind.METHODS) { - throw new AssertionError("Unexpected kind: " + kind); - } - for (TypeElement t : visibleClasses) { - for (Element member : classMap.get(t).members) { - ExecutableElement inheritedMethod = (ExecutableElement)member; - if (utils.elementUtils.overrides(method, inheritedMethod, t)) { - return true; - } - } - } - return false; - } - - /** - * Returns a list of enclosed members for the given type. - * - * @param typeElement the given type - * - * @return a list of enclosed members - */ - public List getMembers(TypeElement typeElement) { - List result = new ArrayList<>(); - if (this.kind == Kind.METHODS) { - for (Element member : classMap.get(typeElement).members) { - ExecutableElement method = (ExecutableElement)member; - if (hasOverridden(method)) { - if (!utils.isSimpleOverride(method)) { - result.add(method); - } - } else { - result.add(method); - } - } - } else { - result.addAll(classMap.get(typeElement).members); - } - return result; - } - - public boolean hasMembers(TypeElement typeElement) { - return !classMap.get(typeElement).members.isEmpty(); - } - - private void fillMemberLevelMap(List list, String level) { - for (Element element : list) { - Object key = getMemberKey(element); - Map memberLevelMap = memberNameMap.get(key); - if (memberLevelMap == null) { - memberLevelMap = new HashMap<>(); - memberNameMap.put(key, memberLevelMap); - } - memberLevelMap.put(element, level); - } - } - - private void purgeMemberLevelMap(Iterable list, String level) { - for (Element element : list) { - Object key = getMemberKey(element); - Map memberLevelMap = memberNameMap.get(key); - if (memberLevelMap != null && level.equals(memberLevelMap.get(element))) - memberLevelMap.remove(element); - } - } - - /** - * Represents a class member. - */ - private class ClassMember { - private Set members; - - public ClassMember(Element element) { - members = new HashSet<>(); - members.add(element); - } - - public boolean isEqual(ExecutableElement method) { - for (Element member : members) { - if (member.getKind() != ElementKind.METHOD) - continue; - ExecutableElement thatMethod = (ExecutableElement) member; - if (utils.executableMembersEqual(method, thatMethod) && - !utils.isSimpleOverride(thatMethod)) { - members.add(method); - return true; - } - } - return false; - } - } - - /** - * A data structure that represents the class members for - * a visible class. - */ - private class ClassMembers { - - /** - * The mapping class, whose inherited members are put in the - * {@link #members} list. - */ - private final TypeElement typeElement; - - /** - * List of members from the mapping class. - */ - private List members = null; - - /** - * Level/Depth of inheritance. - */ - private final String level; - - private ClassMembers(TypeElement mappingClass, String level) { - this.typeElement = mappingClass; - this.level = level; - if (classMap.containsKey(mappingClass) && - level.startsWith(classMap.get(mappingClass).level)) { - //Remove lower level class so that it can be replaced with - //same class found at higher level. - purgeMemberLevelMap(getClassMembers(mappingClass, false), - classMap.get(mappingClass).level); - classMap.remove(mappingClass); - visibleClasses.remove(mappingClass); - } - if (!classMap.containsKey(mappingClass)) { - classMap.put(mappingClass, this); - visibleClasses.add(mappingClass); - } - } - - private void build() { - if (kind == Kind.CONSTRUCTORS) { - addMembers(typeElement); - } else { - mapClass(); - } - } - - private void mapClass() { - addMembers(typeElement); - List interfaces = typeElement.getInterfaces(); - for (TypeMirror anInterface : interfaces) { - String locallevel = level + 1; - ClassMembers cm = new ClassMembers(utils.asTypeElement(anInterface), locallevel); - cm.mapClass(); - } - if (utils.isClass(typeElement)) { - TypeElement superclass = utils.getSuperClass(typeElement); - if (!(superclass == null || typeElement.equals(superclass))) { - ClassMembers cm = new ClassMembers(superclass, level + "c"); - cm.mapClass(); - } - } - } - - /** - * Get all the valid members from the mapping class. Get the list of - * members for the class to be included into(ctii), also get the level - * string for ctii. If mapping class member is not already in the - * inherited member list and if it is visible in the ctii and not - * overridden, put such a member in the inherited member list. - * Adjust member-level-map, class-map. - */ - private void addMembers(TypeElement fromClass) { - List result = new ArrayList<>(); - for (Element element : getClassMembers(fromClass, true)) { - if (memberIsVisible(element)) { - if (!isOverridden(element, level)) { - if (!utils.isHidden(element)) { - result.add(element); - } - } - } - } - if (members != null) { - throw new AssertionError("members should not be null"); - } - members = Collections.unmodifiableList(result); - if (!members.isEmpty()) { - noVisibleMembers = false; - } - fillMemberLevelMap(getClassMembers(fromClass, false), level); - } - - /** - * Is given element visible in given typeElement in terms of inheritance? The given element - * is visible in the given typeElement if it is public or protected and if it is - * package-private if it's containing class is in the same package as the given typeElement. - */ - private boolean memberIsVisible(Element element) { - if (utils.getEnclosingTypeElement(element).equals(VisibleMemberMap.this.typeElement)) { - //Member is in class that we are finding visible members for. - //Of course it is visible. - return true; - } else if (utils.isPrivate(element)) { - //Member is in super class or implemented interface. - //Private, so not inherited. - return false; - } else if (utils.isPackagePrivate(element)) { - //Member is package private. Only return true if its class is in - //same package. - return utils.containingPackage(element).equals(utils.containingPackage(VisibleMemberMap.this.typeElement)); - } else { - //Public members are always inherited. - return true; - } - } - - /** - * Return all available class members. - */ - private List getClassMembers(TypeElement te, boolean filter) { - if (utils.isEnum(te) && kind == Kind.CONSTRUCTORS) { - //If any of these rules are hit, return empty array because - //we don't document these members ever. - return Collections.emptyList(); - } - List list; - switch (kind) { - case ANNOTATION_TYPE_FIELDS: - list = (filter) - ? utils.getAnnotationFields(te) - : utils.getAnnotationFieldsUnfiltered(te); - break; - case ANNOTATION_TYPE_MEMBER_OPTIONAL: - list = utils.isAnnotationType(te) - ? filterAnnotations(te, false) - : Collections.emptyList(); - break; - case ANNOTATION_TYPE_MEMBER_REQUIRED: - list = utils.isAnnotationType(te) - ? filterAnnotations(te, true) - : Collections.emptyList(); - break; - case INNER_CLASSES: - List xlist = filter - ? utils.getInnerClasses(te) - : utils.getInnerClassesUnfiltered(te); - list = new ArrayList<>(xlist); - break; - case ENUM_CONSTANTS: - list = utils.getEnumConstants(te); - break; - case FIELDS: - if (filter) { - list = utils.isAnnotationType(te) - ? utils.getAnnotationFields(te) - : utils.getFields(te); - } else { - list = utils.isAnnotationType(te) - ? utils.getAnnotationFieldsUnfiltered(te) - : utils.getFieldsUnfiltered(te); - } - break; - case CONSTRUCTORS: - list = utils.getConstructors(te); - break; - case METHODS: - list = filter ? utils.getMethods(te) : utils.getMethodsUnfiltered(te); - checkOnPropertiesTags(list); - break; - case PROPERTIES: - list = properties(te, filter); - break; - default: - list = Collections.emptyList(); - } - // Deprected members should be excluded or not? - if (configuration.nodeprecated) { - return utils.excludeDeprecatedMembers(list); - } - return list; - } - - /** - * Filter the annotation type members and return either the required - * members or the optional members, depending on the value of the - * required parameter. - * - * @param typeElement The annotation type to process. - * @param required - * @return the annotation type members and return either the required - * members or the optional members, depending on the value of the - * required parameter. - */ - private List filterAnnotations(TypeElement typeElement, boolean required) { - List members = utils.getAnnotationMethods(typeElement); - List targetMembers = new ArrayList<>(); - for (Element member : members) { - ExecutableElement ee = (ExecutableElement)member; - if ((required && ee.getDefaultValue() == null) - || ((!required) && ee.getDefaultValue() != null)) { - targetMembers.add(member); - } - } - return targetMembers; - } - - /** - * Is member overridden? The member is overridden if it is found in the - * same level hierarchy e.g. member at level "11" overrides member at - * level "111". - */ - private boolean isOverridden(Element element, String level) { - Object key = getMemberKey(element); - Map memberLevelMap = (Map) memberNameMap.get(key); - if (memberLevelMap == null) - return false; - for (String mappedlevel : memberLevelMap.values()) { - if (mappedlevel.equals(STARTLEVEL) - || (level.startsWith(mappedlevel) - && !level.equals(mappedlevel))) { - return true; - } - } - return false; - } - - private List properties(final TypeElement typeElement, final boolean filter) { - final List allMethods = filter - ? utils.getMethods(typeElement) - : utils.getMethodsUnfiltered(typeElement); - final List allFields = utils.getFieldsUnfiltered(typeElement); - - if (propertiesCache.containsKey(typeElement)) { - return propertiesCache.get(typeElement); - } - - final List result = new ArrayList<>(); - - for (final Element propertyMethod : allMethods) { - ExecutableElement ee = (ExecutableElement)propertyMethod; - if (!isPropertyMethod(ee)) { - continue; - } - - final ExecutableElement getter = getterForField(allMethods, ee); - final ExecutableElement setter = setterForField(allMethods, ee); - final VariableElement field = fieldForProperty(allFields, ee); - - addToPropertiesMap(setter, getter, ee, field); - getterSetterMap.put(propertyMethod, new GetterSetter(getter, setter)); - result.add(ee); - } - propertiesCache.put(typeElement, result); - return result; - } - - private void addToPropertiesMap(ExecutableElement setter, - ExecutableElement getter, - ExecutableElement propertyMethod, - VariableElement field) { - if (field == null || utils.getDocCommentTree(field) == null) { - addToPropertiesMap(setter, propertyMethod); - addToPropertiesMap(getter, propertyMethod); - addToPropertiesMap(propertyMethod, propertyMethod); - } else { - addToPropertiesMap(getter, field); - addToPropertiesMap(setter, field); - addToPropertiesMap(propertyMethod, field); - } - } - - private void addToPropertiesMap(Element propertyMethod, - Element commentSource) { - if (null == propertyMethod || null == commentSource) { - return; - } - DocCommentTree docTree = utils.getDocCommentTree(propertyMethod); - - /* The second condition is required for the property buckets. In - * this case the comment is at the property method (not at the field) - * and it needs to be listed in the map. - */ - if ((docTree == null) || propertyMethod.equals(commentSource)) { - classPropertiesMap.put(propertyMethod, commentSource); - } - } - - private ExecutableElement getterForField(List methods, - ExecutableElement propertyMethod) { - final String propertyMethodName = utils.getSimpleName(propertyMethod); - final String fieldName = propertyMethodName.substring(0, - propertyMethodName.lastIndexOf("Property")); - final String fieldNameUppercased = - "" + Character.toUpperCase(fieldName.charAt(0)) - + fieldName.substring(1); - final String getterNamePattern; - final String fieldTypeName = propertyMethod.getReturnType().toString(); - if ("boolean".equals(fieldTypeName) - || fieldTypeName.endsWith("BooleanProperty")) { - getterNamePattern = "(is|get)" + fieldNameUppercased; - } else { - getterNamePattern = "get" + fieldNameUppercased; - } - - for (ExecutableElement method : methods) { - if (Pattern.matches(getterNamePattern, utils.getSimpleName(method))) { - if (method.getParameters().isEmpty() && - utils.isPublic(method) || utils.isProtected(method)) { - return method; - } - } - } - return null; - } - - private ExecutableElement setterForField(List methods, - ExecutableElement propertyMethod) { - final String propertyMethodName = utils.getSimpleName(propertyMethod); - final String fieldName = - propertyMethodName.substring(0, - propertyMethodName.lastIndexOf("Property")); - final String fieldNameUppercased = - "" + Character.toUpperCase(fieldName.charAt(0)) - + fieldName.substring(1); - final String setter = "set" + fieldNameUppercased; - - for (ExecutableElement method : methods) { - if (setter.equals(utils.getSimpleName(method))) { - if (method.getParameters().size() == 1 - && method.getReturnType().getKind() == TypeKind.VOID - && (utils.isPublic(method) || utils.isProtected(method))) { - return method; - } - } - } - return null; - } - - private VariableElement fieldForProperty(List fields, ExecutableElement property) { - - for (VariableElement field : fields) { - final String fieldName = utils.getSimpleName(field); - final String propertyName = fieldName + "Property"; - if (propertyName.equals(utils.getSimpleName(property))) { - return field; - } - } - return null; - } - - private boolean isPropertyMethod(ExecutableElement method) { - if (!configuration.javafx) { - return false; - } - if (!utils.getSimpleName(method).endsWith("Property")) { - return false; - } - - if (!memberIsVisible(method)) { - return false; - } - - if (GETTERSETTERPATTERN.matcher(utils.getSimpleName(method)).matches()) { - return false; - } - if (!method.getTypeParameters().isEmpty()) { - return false; - } - return method.getParameters().isEmpty() - && method.getReturnType().getKind() != TypeKind.VOID; - } - - private void checkOnPropertiesTags(List members) { - for (Element e: members) { - ExecutableElement ee = (ExecutableElement)e; - if (utils.isIncluded(ee)) { - CommentHelper ch = utils.getCommentHelper(ee); - for (DocTree tree: utils.getBlockTags(ee)) { - String tagName = ch.getTagName(tree); - if (tagName.equals("@propertySetter") - || tagName.equals("@propertyGetter") - || tagName.equals("@propertyDescription")) { - if (!isPropertyGetterOrSetter(members, ee)) { - messages.warning(ch.getDocTreePath(tree), - "doclet.javafx_tag_misuse"); - } - break; - } - } - } - } - } - - private boolean isPropertyGetterOrSetter(List members, - ExecutableElement method) { - String propertyName = utils.propertyName(method); - if (!propertyName.isEmpty()) { - String propertyMethodName = propertyName + "Property"; - for (Element member: members) { - if (utils.getSimpleName(member).equals(propertyMethodName)) { - return true; - } - } - } - return false; - } - } - - public class GetterSetter { - private final Element getter; - private final Element setter; - - public GetterSetter(Element getter, Element setter) { - this.getter = getter; - this.setter = setter; - } - - public Element getGetter() { - return getter; - } - - public Element getSetter() { - return setter; - } - } - - /** - * Return true if this map has no visible members. - * - * @return true if this map has no visible members. - */ - public boolean noVisibleMembers() { - return noVisibleMembers; - } - - private ClassMember getClassMember(ExecutableElement member) { - for (Object key : memberNameMap.keySet()) { - if (key instanceof String) { - continue; - } - if (((ClassMember) key).isEqual(member)) { - return (ClassMember) key; - } - } - return new ClassMember(member); - } - - /** - * Return the key to the member map for the given member. - */ - private Object getMemberKey(Element element) { - if (utils.isConstructor(element)) { - return utils.getSimpleName(element) + utils.flatSignature((ExecutableElement)element); - } else if (utils.isMethod(element)) { - return getClassMember((ExecutableElement) element); - } else if (utils.isField(element) || utils.isEnumConstant(element) || utils.isAnnotationType(element)) { - return utils.getSimpleName(element); - } else { // it's a class or interface - String classOrIntName = utils.getSimpleName(element); - //Strip off the containing class name because we only want the member name. - classOrIntName = classOrIntName.indexOf('.') != 0 - ? classOrIntName.substring(classOrIntName.lastIndexOf('.')) - : classOrIntName; - return "clint" + classOrIntName; - } - } -} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java new file mode 100644 index 00000000000..a43104bd598 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java @@ -0,0 +1,992 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.doclets.toolkit.util; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.SimpleElementVisitor9; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; +import jdk.javadoc.internal.doclets.toolkit.PropertyUtils; + +/** + * This class computes the main data structure for the doclet's + * operations. Essentially, the implementation encapsulating the + * javax.lang.models view of what can be documented about a + * type element's members. + *

+ * The general operations are as follows: + *

+ * Members: these are the members from jx.l.m's view but + * are structured along the kinds of this class. + *

+ * Extra Members: these are members enclosed in an undocumented + * package-private type element, and may not be linkable (or documented), + * however, the members of such a type element may be documented, as if + * declared in the sub type, only if the enclosing type is not being + * documented by a filter such as -public, -protected, etc. + *

+ * Visible Members: these are the members that are "visible" + * and available and should be documented, in a type element. + *

+ * The basic rule for computation: when considering a type element, + * besides its immediate direct types and interfaces, the computation + * should not expand to any other type in the inheritance hierarchy. + *

+ * This table generates all the data structures it needs for each + * type, as its own view, and will present some form of this to the + * doclet as and when required to. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + */ + +public class VisibleMemberTable { + + public enum Kind { + INNER_CLASSES, + ENUM_CONSTANTS, + FIELDS, + CONSTRUCTORS, + METHODS, + ANNOTATION_TYPE_FIELDS, + ANNOTATION_TYPE_MEMBER_OPTIONAL, + ANNOTATION_TYPE_MEMBER_REQUIRED, + PROPERTIES; + + public static final EnumSet summarySet = EnumSet.range(INNER_CLASSES, METHODS); + public static final EnumSet detailSet = EnumSet.range(ENUM_CONSTANTS, METHODS); + } + + final TypeElement te; + final TypeElement parent; + + final BaseConfiguration config; + final Utils utils; + final VisibleMemberCache mcache; + + private List allSuperclasses; + private List allSuperinterfaces; + private List parents; + + + private Map> extraMembers = new EnumMap<>(Kind.class); + private Map> visibleMembers = null; + private Map propertyMap = new HashMap<>(); + + // Keeps track of method overrides + Map overriddenMethodTable + = new LinkedHashMap<>(); + + protected VisibleMemberTable(TypeElement typeElement, BaseConfiguration configuration, + VisibleMemberCache mcache) { + config = configuration; + utils = configuration.utils; + te = typeElement; + parent = utils.getSuperClass(te); + this.mcache = mcache; + allSuperclasses = new ArrayList<>(); + allSuperinterfaces = new ArrayList<>(); + parents = new ArrayList<>(); + } + + private synchronized void ensureInitialized() { + if (visibleMembers != null) + return; + + visibleMembers = new EnumMap<>(Kind.class); + for (Kind kind : Kind.values()) { + visibleMembers.put(kind, new ArrayList<>()); + } + computeParents(); + computeVisibleMembers(); + } + + List getExtraMembers(Kind kind) { + ensureInitialized(); + return visibleMembers.getOrDefault(kind, Collections.emptyList()); + } + + List getAllSuperclasses() { + ensureInitialized(); + return allSuperclasses; + } + + List getAllSuperinterfaces() { + ensureInitialized(); + return allSuperinterfaces; + } + + /** + * Returns a list of all visible enclosed members of a type element, + * and inherited members. + *

+ * Notes: + * a. The list may or may not contain simple overridden methods. + * A simple overridden method is one that overrides a super method + * with no specification changes as indicated by the existence of a + * sole @inheritDoc or devoid of any API commments. + *

+ * b.The list may contain (extra) members, inherited by inaccessible + * super types, primarily package private types. These members are + * required to be documented in the subtype when the super type is + * not documented. + * + * @param kind the member kind + * @return a list of all visible members + */ + public List getAllVisibleMembers(Kind kind) { + ensureInitialized(); + return visibleMembers.getOrDefault(kind, Collections.emptyList()); + } + + /** + * Returns a list of visible enclosed members of a specified kind, + * filtered by the specified predicate. + * @param kind the member kind + * @param p the predicate used to filter the output + * @return a list of visible enclosed members + */ + public List getVisibleMembers(Kind kind, Predicate p) { + ensureInitialized(); + + return visibleMembers.getOrDefault(kind, Collections.emptyList()).stream() + .filter(p) + .collect(Collectors.toList()); + } + + /** + * Returns a list of all enclosed members including any extra members. + * Typically called by various builders. + * + * @param kind the member kind + * @return a list of visible enclosed members + */ + public List getVisibleMembers(Kind kind) { + Predicate declaredAndLeafMembers = e -> { + TypeElement encl = utils.getEnclosingTypeElement(e); + return encl == te || isUndocumentedEnclosure(encl); + }; + return getVisibleMembers(kind, declaredAndLeafMembers); + } + + /** + * Returns a list of visible enclosed members of given kind, + * declared in this type element, and does not include + * any inherited members or extra members. + * + * @return a list of visible enclosed members in this type + */ + public List getMembers(Kind kind) { + Predicate onlyLocallyDeclaredMembers = e -> utils.getEnclosingTypeElement(e) == te; + return getVisibleMembers(kind, onlyLocallyDeclaredMembers); + } + + /** + * Returns the overridden method, if it is simply overridding or the + * method is a member of a package private type, this method is + * primarily used to determine the location of a possible comment. + * + * @param e the method to check + * @return the method found or null + */ + public ExecutableElement getOverriddenMethod(ExecutableElement e) { + ensureInitialized(); + + OverridingMethodInfo found = overriddenMethodTable.get(e); + if (found != null && (found.simpleOverride || isUndocumentedEnclosure(utils.getEnclosingTypeElement(e)))) { + return found.overrider; + } + return null; + } + + /** + * Returns the simply overridden method. + * @param e the method to check + * @return the overridden method or null + */ + public ExecutableElement getsimplyOverriddenMethod(ExecutableElement e) { + ensureInitialized(); + + OverridingMethodInfo found = overriddenMethodTable.get(e); + if (found != null && found.simpleOverride) { + return found.overrider; + } + return null; + } + + /** + * Returns a set of visible type elements in this type element's lineage. + *

+ * This method returns the super-types in the inheritance + * order C, B, A, j.l.O. The super-interfaces however are + * alpha sorted and appended to the resulting set. + * + * @return the list of visible classes in this map. + */ + public Set getVisibleTypeElements() { + ensureInitialized(); + Set result = new LinkedHashSet<>(); + + // Add this type element first. + result.add(te); + + // Add the super classes. + allSuperclasses.stream() + .map(vmt -> vmt.te) + .forEach(result::add); + + // ... and finally the sorted super interfaces. + allSuperinterfaces.stream() + .map(vmt -> vmt.te) + .sorted(utils.makeGeneralPurposeComparator()) + .forEach(result::add); + + return result; + } + + /** + * Returns true if this table contains visible members. + * + * @return true if visible members are present. + */ + public boolean hasVisibleMembers() { + for (Kind kind : Kind.values()) { + if (hasVisibleMembers(kind)) + return true; + } + return false; + } + + /** + * Returns true if this table contains visible members of + * the specified kind, including inhertied members. + * + * @return true if visible members are present. + */ + public boolean hasVisibleMembers(Kind kind) { + ensureInitialized(); + List elements = visibleMembers.get(kind); + return elements != null && !elements.isEmpty(); + } + + /** + * Returns the property field associated with the property method. + * @param propertyMethod the identifying property method + * @return the field or null if absent + */ + public VariableElement getPropertyField(ExecutableElement propertyMethod) { + ensureInitialized(); + PropertyMembers pm = propertyMap.get(propertyMethod); + return pm == null ? null : pm.field; + } + + /** + * Returns the getter method associated with the property method. + * @param propertyMethod the identifying property method + * @return the getter or null if absent + */ + public ExecutableElement getPropertyGetter(ExecutableElement propertyMethod) { + ensureInitialized(); + PropertyMembers pm = propertyMap.get(propertyMethod); + return pm == null ? null : pm.getter; + } + + /** + * Returns the setter method associated with the property method. + * @param propertyMethod the identifying property method + * @return the setter or null if absent + */ + public ExecutableElement getPropertySetter(ExecutableElement propertyMethod) { + ensureInitialized(); + PropertyMembers pm = propertyMap.get(propertyMethod); + return pm == null ? null : pm.setter; + } + + boolean isUndocumentedEnclosure(TypeElement encl) { + return utils.isPackagePrivate(encl) && !utils.isLinkable(encl); + } + + private void computeParents() { + for (TypeMirror intfType : te.getInterfaces()) { + TypeElement intfc = utils.asTypeElement(intfType); + if (intfc != null) { + VisibleMemberTable vmt = mcache.getVisibleMemberTable(intfc); + allSuperinterfaces.add(vmt); + parents.add(vmt); + allSuperinterfaces.addAll(vmt.getAllSuperinterfaces()); + } + } + + if (parent != null) { + VisibleMemberTable vmt = mcache.getVisibleMemberTable(parent); + allSuperclasses.add(vmt); + allSuperclasses.addAll(vmt.getAllSuperclasses()); + // Add direct super interfaces of a super class, if any. + allSuperinterfaces.addAll(vmt.getAllSuperinterfaces()); + parents.add(vmt); + } + } + + private void computeVisibleMembers() { + + // Note: these have some baggage, and are redundant, + // allow this to be GC'ed. + LocalMemberTable lmt = new LocalMemberTable(); + + for (Kind k : Kind.values()) { + computeLeafMembers(lmt, k); + computeVisibleMembers(lmt, k); + } + // All members have been computed, compute properties. + computeVisibleProperties(lmt); + } + + private void computeLeafMembers(LocalMemberTable lmt, Kind kind) { + List list = new ArrayList<>(); + if (isUndocumentedEnclosure(te)) { + list.addAll(lmt.getOrderedMembers(kind)); + } + parents.forEach(pvmt -> { + list.addAll(pvmt.getExtraMembers(kind)); + }); + extraMembers.put(kind, Collections.unmodifiableList(list)); + } + + void computeVisibleMembers(LocalMemberTable lmt, Kind kind) { + switch (kind) { + case FIELDS: case INNER_CLASSES: + computeVisibleFieldsAndInnerClasses(lmt, kind); + return; + + case METHODS: + computeVisibleMethods(lmt); + return; + + // Defer properties related computations for later. + case PROPERTIES: + return; + + default: + List list = lmt.getOrderedMembers(kind).stream() + .filter(this::mustDocument) + .collect(Collectors.toList()); + visibleMembers.put(kind, Collections.unmodifiableList(list)); + break; + } + } + + private boolean mustDocument(Element e) { + return !utils.hasHiddenTag(e) && utils.shouldDocument(e); + } + + private boolean allowInheritedMembers(Element e, Kind kind, LocalMemberTable lmt) { + return isInherited(e) && !isMemberHidden(e, kind, lmt); + } + + private boolean isInherited(Element e) { + if (utils.isPrivate(e)) + return false; + + if (utils.isPackagePrivate(e)) + // Allowed iff this type-element is in the same package as the element + return utils.containingPackage(e).equals(utils.containingPackage(te)); + + return true; + } + + private boolean isMemberHidden(Element inheritedMember, Kind kind, LocalMemberTable lmt) { + Elements elementUtils = config.docEnv.getElementUtils(); + switch(kind) { + default: + List list = lmt.getMembers(inheritedMember, kind); + if (list.isEmpty()) + return false; + return elementUtils.hides(list.get(0), inheritedMember); + case METHODS: case CONSTRUCTORS: // Handled elsewhere. + throw new IllegalArgumentException("incorrect kind"); + } + } + + private void computeVisibleFieldsAndInnerClasses(LocalMemberTable lmt, Kind kind) { + Set result = new LinkedHashSet<>(); + for (VisibleMemberTable pvmt : parents) { + result.addAll(pvmt.getExtraMembers(kind)); + result.addAll(pvmt.getAllVisibleMembers(kind)); + } + + // Filter out members in the inherited list that are hidden + // by this type or should not be inherited at all. + List list = result.stream() + .filter(e -> allowInheritedMembers(e, kind, lmt)).collect(Collectors.toList()); + + // Prefix local results first + list.addAll(0, lmt.getOrderedMembers(kind)); + + // Filter out elements that should not be documented + list = list.stream() + .filter(this::mustDocument) + .collect(Collectors.toList()); + + visibleMembers.put(kind, Collections.unmodifiableList(list)); + } + + private void computeVisibleMethods(LocalMemberTable lmt) { + Set inheritedMethods = new LinkedHashSet<>(); + Map> overriddenByTable = new HashMap<>(); + for (VisibleMemberTable pvmt : parents) { + // Merge the lineage overrides into local table + pvmt.overriddenMethodTable.entrySet().forEach(e -> { + OverridingMethodInfo p = e.getValue(); + if (!p.simpleOverride) { // consider only real overrides + List list = overriddenByTable.computeIfAbsent(p.overrider, + k -> new ArrayList<>()); + list.add(e.getKey()); + } + }); + inheritedMethods.addAll(pvmt.getAllVisibleMembers(Kind.METHODS)); + + // Copy the extra members (if any) from the lineage. + if (!utils.shouldDocument(pvmt.te)) { + List extraMethods = pvmt.getExtraMembers(Kind.METHODS); + + if (lmt.getOrderedMembers(Kind.METHODS).isEmpty()) { + inheritedMethods.addAll(extraMethods); + continue; + } + + // Check if an extra-method ought to percolate through. + for (Element extraMethod : extraMethods) { + boolean found = false; + + List lmethods = lmt.getMembers(extraMethod, Kind.METHODS); + for (Element lmethod : lmethods) { + ExecutableElement method = (ExecutableElement)lmethod; + found = utils.elementUtils.overrides(method, + (ExecutableElement)extraMethod, te); + if (found) + break; + } + if (!found) + inheritedMethods.add(extraMethod); + } + } + } + + // Filter out inherited methods that: + // a. cannot override (private instance members) + // b. are overridden and should not be visible in this type + // c. are hidden in the type being considered + // see allowInheritedMethods, which performs the above actions + List list = inheritedMethods.stream() + .filter(e -> allowInheritedMethods((ExecutableElement)e, overriddenByTable, lmt)) + .collect(Collectors.toList()); + + // Filter out the local methods, that do not override or simply + // overrides a super method, or those methods that should not + // be visible. + Predicate isVisible = m -> { + OverridingMethodInfo p = overriddenMethodTable.getOrDefault(m, null); + return p == null || !p.simpleOverride; + }; + List mlist = lmt.getOrderedMembers(Kind.METHODS); + List llist = mlist.stream() + .map(m -> (ExecutableElement)m) + .filter(isVisible) + .collect(Collectors.toList()); + + // Merge the above lists, making sure the local methods precede + // the others + list.addAll(0, llist); + + // Final filtration of elements + list = list.stream() + .filter(this::mustDocument) + .collect(Collectors.toList()); + + visibleMembers.put(Kind.METHODS, Collections.unmodifiableList(list)); + + // Copy over overridden tables from the lineage, and finish up. + for (VisibleMemberTable pvmt : parents) { + overriddenMethodTable.putAll(pvmt.overriddenMethodTable); + } + overriddenMethodTable = Collections.unmodifiableMap(overriddenMethodTable); + } + + boolean isEnclosureInterface(Element e) { + TypeElement enclosing = utils.getEnclosingTypeElement(e); + return utils.isInterface(enclosing); + } + + boolean allowInheritedMethods(ExecutableElement inheritedMethod, + Map> inheritedOverriddenTable, + LocalMemberTable lmt) { + + if (!isInherited(inheritedMethod)) + return false; + + final boolean haveStatic = utils.isStatic(inheritedMethod); + final boolean inInterface = isEnclosureInterface(inheritedMethod); + + // Static methods in interfaces are never documented. + if (haveStatic && inInterface) { + return false; + } + + // Multiple-Inheritance: remove the interface method that may have + // been overridden by another interface method in the hierarchy + // + // Note: The following approach is very simplistic and is compatible + // with old VMM. A future enhancement, may include a contention breaker, + // to correctly eliminate those methods that are merely definitions + // in favor of concrete overriding methods, for instance those that have + // API documentation and are not abstract OR default methods. + if (inInterface) { + List list = inheritedOverriddenTable.get(inheritedMethod); + if (list != null) { + boolean found = list.stream() + .anyMatch(this::isEnclosureInterface); + if (found) + return false; + } + } + + Elements elementUtils = config.docEnv.getElementUtils(); + + // Check the local methods in this type. + List lMethods = lmt.getMembers(inheritedMethod, Kind.METHODS); + for (Element lMethod : lMethods) { + // Ignore private methods or those methods marked with + // a "hidden" tag. + if (utils.isPrivate(lMethod)) + continue; + + // Remove methods that are "hidden", in JLS terms. + if (haveStatic && utils.isStatic(lMethod) && + elementUtils.hides(lMethod, inheritedMethod)) { + return false; + } + + // Check for overriding methods. + if (elementUtils.overrides((ExecutableElement)lMethod, inheritedMethod, + utils.getEnclosingTypeElement(lMethod))) { + + // Disallow package-private super methods to leak in + TypeElement encl = utils.getEnclosingTypeElement(inheritedMethod); + if (isUndocumentedEnclosure(encl)) { + overriddenMethodTable.computeIfAbsent((ExecutableElement)lMethod, + l -> new OverridingMethodInfo(inheritedMethod, false)); + return false; + } + boolean simpleOverride = utils.isSimpleOverride((ExecutableElement)lMethod); + overriddenMethodTable.computeIfAbsent((ExecutableElement)lMethod, + l -> new OverridingMethodInfo(inheritedMethod, simpleOverride)); + return simpleOverride; + } + } + return true; + } + + /* + * This class encapsulates the details of local members, orderedMembers + * contains the members in the declaration order, additionally a + * HashMap is maintained for performance optimization to lookup + * members. As a future enhancement is perhaps to consolidate the ordering + * into a Map, capturing the insertion order, thereby eliminating an + * ordered list. + */ + class LocalMemberTable { + + // Maintains declaration order + private final Map> orderedMembers; + + // Performance optimization + private final Map>> memberMap; + + LocalMemberTable() { + orderedMembers = new EnumMap<>(Kind.class); + memberMap = new EnumMap<>(Kind.class); + + List elements = te.getEnclosedElements(); + for (Element e : elements) { + if (config.nodeprecated && utils.isDeprecated(e)) { + continue; + } + switch (e.getKind()) { + case CLASS: + case INTERFACE: + case ENUM: + case ANNOTATION_TYPE: + addMember(e, Kind.INNER_CLASSES); + break; + case FIELD: + addMember(e, Kind.FIELDS); + addMember(e, Kind.ANNOTATION_TYPE_FIELDS); + break; + case METHOD: + ExecutableElement ee = (ExecutableElement)e; + if (utils.isAnnotationType(te)) { + addMember(e, ee.getDefaultValue() == null + ? Kind.ANNOTATION_TYPE_MEMBER_REQUIRED + : Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL); + } + addMember(e, Kind.METHODS); + break; + case CONSTRUCTOR: + if (!utils.isEnum(te)) + addMember(e, Kind.CONSTRUCTORS); + break; + case ENUM_CONSTANT: + addMember(e, Kind.ENUM_CONSTANTS); + break; + } + } + + // Freeze the data structures + for (Kind kind : Kind.values()) { + orderedMembers.computeIfPresent(kind, (k, v) -> Collections.unmodifiableList(v)); + orderedMembers.computeIfAbsent(kind, t -> Collections.emptyList()); + + memberMap.computeIfPresent(kind, (k, v) -> Collections.unmodifiableMap(v)); + memberMap.computeIfAbsent(kind, t -> Collections.emptyMap()); + } + } + + String getMemberKey(Element e) { + return new SimpleElementVisitor9() { + @Override + public String visitExecutable(ExecutableElement e, Void aVoid) { + return e.getSimpleName() + ":" + e.getParameters().size(); + } + + @Override + protected String defaultAction(Element e, Void aVoid) { + return e.getSimpleName().toString(); + } + }.visit(e); + } + + void addMember(Element e, Kind kind) { + List list = orderedMembers.computeIfAbsent(kind, k -> new ArrayList<>()); + list.add(e); + + Map> map = memberMap.computeIfAbsent(kind, k -> new HashMap<>()); + list = map.computeIfAbsent(getMemberKey(e), l -> new ArrayList<>()); + list.add(e); + } + + List getOrderedMembers(Kind kind) { + return orderedMembers.get(kind); + } + + List getMembers(Element e, Kind kind) { + String key = getMemberKey(e); + return getMembers(key, kind); + } + + List getMembers(String key, Kind kind) { + Map > map = memberMap.get(kind); + return map.getOrDefault(key, Collections.emptyList()); + } + + List getPropertyMethods(String methodName, int argcount) { + return getMembers(methodName + ":" + argcount, Kind.METHODS).stream() + .filter(m -> (utils.isPublic(m) || utils.isProtected(m))) + .collect(Collectors.toList()); + } + } + + /** + * The properties triad for a property method. + */ + static class PropertyMembers { + final VariableElement field; + final ExecutableElement getter; + final ExecutableElement setter; + + PropertyMembers(VariableElement field, ExecutableElement getter, ExecutableElement setter) { + this.field = field; + this.getter = getter; + this.setter = setter; + } + + public String toString() { + return ("field: " + field + ", getter: " + getter + ", setter: " + setter); + } + } + + /* + * JavaFX convention notes. + * A JavaFX property-method is a method, which ends with "Property" in + * its name, takes no parameters and typically returns a subtype of javafx.beans. + * ReadOnlyProperty, in the strictest sense. However, it may not always + * be possible for the doclet to have access to j.b.ReadOnlyProperty, + * for this reason the strict check is disabled via an undocumented flag. + * + * Note, a method should not be considered as a property-method, + * if it satisfied the previously stated conditions AND if the + * method begins with "set", "get" or "is". + * + * Supposing we have {@code BooleanProperty acmeProperty()}, then the + * property-name is "acme". + * + * Property field, one may or may not exist and could be private, and + * should match the property-method. + * + * A property-setter is a method starting with "set", and the + * first character of the upper-cased starting character of the property name, the + * method must take 1 argument and must return a void. + * + * Using the above example {@code void setAcme(Something s)} can be + * considered as a property-setter of the property "acme". + * + * A property-getter is a method starting with "get" and the first character + * upper-cased property-name, having no parameters. A method that does not take any + * parameters and starting with "is" and an upper-cased property-name, + * returning a primitive type boolean or BooleanProperty can also be + * considered as a getter, however there must be only one getter for every property. + * + * For example {@code Object getAcme()} is a property-getter, and + * {@code boolean isFoo()} + */ + private void computeVisibleProperties(LocalMemberTable lmt) { + if (!config.javafx) + return; + + PropertyUtils pUtils = config.propertyUtils; + List list = visibleMembers.getOrDefault(Kind.METHODS, Collections.emptyList()) + .stream() + .map(m -> (ExecutableElement)m) + .filter(pUtils::isPropertyMethod) + .collect(Collectors.toList()); + + visibleMembers.put(Kind.PROPERTIES, Collections.unmodifiableList(list)); + + List propertyMethods = list.stream() + .filter(e -> utils.getEnclosingTypeElement(e) == te) + .collect(Collectors.toList()); + + // Compute additional properties related sundries. + for (ExecutableElement propertyMethod : propertyMethods) { + String baseName = pUtils.getBaseName(propertyMethod); + List flist = lmt.getMembers(baseName, Kind.FIELDS); + Element field = flist.isEmpty() ? null : flist.get(0); + + Element getter = null, setter = null; + List found = lmt.getPropertyMethods(pUtils.getGetName(propertyMethod), 0); + if (!found.isEmpty()) { + // Getters have zero params, no overloads! pick the first. + getter = found.get(0); + } + if (getter == null) { + // Check if isProperty methods are present ? + found = lmt.getPropertyMethods(pUtils.getIsName(propertyMethod), 0); + if (!found.isEmpty()) { + String propertyTypeName = propertyMethod.getReturnType().toString(); + // Check if the return type of property method matches an isProperty method. + if (pUtils.hasIsMethod(propertyMethod)) { + // Getters have zero params, no overloads!, pick the first. + getter = found.get(0); + } + } + } + found = lmt.getPropertyMethods(pUtils.getSetName(propertyMethod), 1); + if (found != null) { + for (Element e : found) { + if (pUtils.isValidSetterMethod((ExecutableElement)e)) { + setter = e; + break; + } + } + } + + propertyMap.put(propertyMethod, new PropertyMembers((VariableElement)field, + (ExecutableElement)getter, (ExecutableElement)setter)); + + // Debugging purposes + // System.out.println("te: " + te + ": " + utils.getEnclosingTypeElement(propertyMethod) + + // ":" + propertyMethod.toString() + "->" + propertyMap.get(propertyMethod)); + } + } + + + // Future cleanups + + Map> implementMethodsFinders = new HashMap<>(); + + private ImplementedMethods getImplementedMethodsFinder(ExecutableElement method) { + SoftReference imf = implementMethodsFinders.get(method); + // IMF does not exist or referent was gc'ed away ? + if (imf == null || imf.get() == null) { + imf = new SoftReference<>(new ImplementedMethods(method)); + implementMethodsFinders.put(method, imf); + } + return imf.get(); + } + + public List getImplementedMethods(ExecutableElement method) { + ImplementedMethods imf = getImplementedMethodsFinder(method); + return imf.getImplementedMethods().stream() + .filter(m -> getsimplyOverriddenMethod(m) == null) + .collect(Collectors.toList()); + } + + public TypeMirror getImplementedMethodHolder(ExecutableElement method, + ExecutableElement implementedMethod) { + ImplementedMethods imf = getImplementedMethodsFinder(method); + return imf.getMethodHolder(implementedMethod); + } + + private class ImplementedMethods { + + private final Map interfaces = new HashMap<>(); + private final List methlist = new ArrayList<>(); + private final TypeElement typeElement; + private final ExecutableElement method; + + public ImplementedMethods(ExecutableElement method) { + this.method = method; + typeElement = utils.getEnclosingTypeElement(method); + Set intfacs = utils.getAllInterfaces(typeElement); + /* + * Search for the method in the list of interfaces. If found check if it is + * overridden by any other subinterface method which this class + * implements. If it is not overidden, add it in the method list. + * Do this recursively for all the extended interfaces for each interface + * from the list. + */ + for (TypeMirror interfaceType : intfacs) { + ExecutableElement found = utils.findMethod(utils.asTypeElement(interfaceType), method); + if (found != null) { + removeOverriddenMethod(found); + if (!overridingMethodFound(found)) { + methlist.add(found); + interfaces.put(found, interfaceType); + } + } + } + } + + /** + * Return the list of interface methods which the method passed in the + * constructor is implementing. The search/build order is as follows: + *

+         * 1. Search in all the immediate interfaces which this method's class is
+         *    implementing. Do it recursively for the superinterfaces as well.
+         * 2. Traverse all the superclasses and search recursively in the
+         *    interfaces which those superclasses implement.
+         *
+ * + * @return SortedSet of implemented methods. + */ + List getImplementedMethods() { + return methlist; + } + + TypeMirror getMethodHolder(ExecutableElement ee) { + return interfaces.get(ee); + } + + /** + * Search in the method list and check if it contains a method which + * is overridden by the method as parameter. If found, remove the + * overridden method from the method list. + * + * @param method Is this method overriding a method in the method list. + */ + private void removeOverriddenMethod(ExecutableElement method) { + TypeElement overriddenClass = utils.overriddenClass(method); + if (overriddenClass != null) { + for (int i = 0; i < methlist.size(); i++) { + TypeElement te = utils.getEnclosingTypeElement(methlist.get(i)); + if (te == overriddenClass || utils.isSubclassOf(overriddenClass, te)) { + methlist.remove(i); // remove overridden method + return; + } + } + } + } + + /** + * Search in the already found methods' list and check if it contains + * a method which is overriding the method parameter or is the method + * parameter itself. + * + * @param method method to be searched + */ + private boolean overridingMethodFound(ExecutableElement method) { + TypeElement containingClass = utils.getEnclosingTypeElement(method); + for (ExecutableElement listmethod : methlist) { + if (containingClass == utils.getEnclosingTypeElement(listmethod)) { + // it's the same method. + return true; + } + TypeElement te = utils.overriddenClass(listmethod); + if (te == null) { + continue; + } + if (te == containingClass || utils.isSubclassOf(te, containingClass)) { + return true; + } + } + return false; + } + } + + /** + * A simple container to encapsulate an overriding method + * and the type of override. + */ + static class OverridingMethodInfo { + final ExecutableElement overrider; + final boolean simpleOverride; + + public OverridingMethodInfo(ExecutableElement overrider, boolean simpleOverride) { + this.overrider = overrider; + this.simpleOverride = simpleOverride; + } + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestFxProperties.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestFxProperties.java new file mode 100644 index 00000000000..02d984cd584 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestFxProperties.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8025091 + * @summary Tests the basic selection of FX related property methods, fields, + * setters and getters, by executing this test in the strict mode. + * @library ../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build JavadocTester propgen.PropGen + * @run main TestFxProperties + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class TestFxProperties extends JavadocTester { + + public static void main(String... args) throws Exception { + TestFxProperties tester = new TestFxProperties(); + if (!tester.sanity()) { + return; + } + tester.runTests(); + } + + // Check if FX modules are available. + boolean sanity() { + ClassLoader cl = this.getClass().getClassLoader(); + try { + cl.loadClass("javafx.beans.Observable"); + } catch (ClassNotFoundException cnfe) { + System.out.println("Note: javafx.beans.Observable: not found, test passes vacuously"); + return false; + } + return true; + } + + @Test + void test1() throws Exception { + Path srcdir = Paths.get("src-propgen"); + Files.createDirectory(srcdir); + new propgen.PropGen(srcdir).run(); + Path srcfile = Paths.get(srcdir.toString(), "Demo.java"); + + javadoc("-d", "out-propgen", + "--javafx", + srcfile.toString()); + checkExit(Exit.OK); + checkOrder("Demo.html", + "PROPERTY SUMMARY", + "Property for fgp.", + "Property for fgsp.", + "Property for fp.", + "Property for fsp.", + "Property for gp.", + "Property for gsp.", + "Property for p.", + "Property for sp.", + "FIELD SUMMARY", + "Field for f.", + "Field for fg.", + "Field for fgp.", + "Field for fgs.", + "Field for fgsp.", + "Field for fp.", + "Field for fs.", + "Field for fsp.", + "CONSTRUCTOR SUMMARY" + ); + + checkOrder("Demo.html", + "METHOD SUMMARY", + "Getter for fg.", + "Getter for fgp.", + "Getter for fgs.", + "Getter for fgsp.", + "Getter for g.", + "Getter for gp.", + "Getter for gs.", + "Getter for gsp.", + "Setter for fgs.", + "Setter for fgsp.", + "Setter for fs.", + "Setter for fsp.", + "Setter for gs.", + "Setter for gsp.", + "Setter for s.", + "Setter for sp.", + "Methods inherited"); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index b4eed61895c..62e5b1ae269 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -24,7 +24,7 @@ /* * @test * @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363 - * 8167967 8172528 8175200 8178830 8182257 8186332 8182765 + * 8167967 8172528 8175200 8178830 8182257 8186332 8182765 8025091 * @summary Test of the JavaFX doclet features. * @author jvalenta * @library ../lib @@ -45,6 +45,7 @@ public class TestJavaFX extends JavadocTester { javadoc("-d", "out1", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "-package", "pkg1"); checkExit(Exit.OK); @@ -174,6 +175,7 @@ public class TestJavaFX extends JavadocTester { "-html4", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "-package", "pkg1"); checkExit(Exit.OK); @@ -200,6 +202,7 @@ public class TestJavaFX extends JavadocTester { javadoc("-d", "out2a", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "-package", "pkg2"); checkExit(Exit.OK); @@ -255,6 +258,7 @@ public class TestJavaFX extends JavadocTester { "-html4", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "-package", "pkg2"); checkExit(Exit.OK); @@ -390,6 +394,7 @@ public class TestJavaFX extends JavadocTester { void test4() { javadoc("-d", "out4", "--javafx", + "--disable-javafx-strict-checks", "-Xdoclint:none", "-sourcepath", testSrc, "-package", diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/C.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/C.java index e2cf8ca15af..0ed29dd8288 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/C.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/pkg1/C.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,27 +60,28 @@ public class C { public final void setRate(double value) {} - public final double getRate() {} + public final double getRate() { return 1.0d; } - public final DoubleProperty rateProperty() {} + public final DoubleProperty rateProperty() { return null; } private BooleanProperty paused; public final void setPaused(boolean value) {} - public final double isPaused() {} + public final double isPaused() { return 3.14d; } /** * Defines if paused. The second line. * @defaultValue false + * @return foo */ - public final BooleanProperty pausedProperty() {} + public final BooleanProperty pausedProperty() { return null; } class DoubleProperty {} class BooleanProperty {} - public final BooleanProperty setTestMethodProperty() {} + public final BooleanProperty setTestMethodProperty() { return null; } private class Inner { private BooleanProperty testMethodProperty() {} @@ -94,8 +95,8 @@ public class C { public final void setRate(double value) {} - public final double getRate() {} + public final double getRate() { return 3.14d; } - public final DoubleProperty rateProperty() {} + public final DoubleProperty rateProperty() { return null; } } } diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/propgen/PropGen.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/propgen/PropGen.java new file mode 100644 index 00000000000..4bb22b29de7 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/propgen/PropGen.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package propgen; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.EnumSet; +import java.util.Set; +import java.util.stream.Collectors; + +public class PropGen { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws IOException { + new PropGen().run(); + } + + final PrintStream out; + + final Path outFile; + final ByteArrayOutputStream baos; + + PropGen() { + out = System.out; + outFile = null; + baos = null; + } + + public PropGen(Path outDir) throws IOException { + outFile = Paths.get(outDir.toString(), "Demo.java"); + baos = new ByteArrayOutputStream(); + out = new PrintStream(baos); + } + + enum Kind { + FIELD(1), + GETTER(2), + SETTER(4), + PROPERTY(8); + Kind(int bit) { + this.bit = bit; + } + int bit; + } + + public void run() throws IOException { + out.println("import javafx.beans.property.Property;"); + out.println("public class Demo {"); + for (int i = 1; i < 16; i++) { + Set set = EnumSet.noneOf(Kind.class); + for (Kind k : Kind.values()) { + if ((i & k.bit) == k.bit) { + set.add(k); + } + } + addItems(set); + } + out.println("}"); + if (baos != null && outFile != null) { + Files.write(outFile, baos.toByteArray()); + } + } + + void addItems(Set kinds) { + String name = kinds.stream() + .map(k -> k.name()) + .map(s -> s.substring(0, 1)) + .collect(Collectors.joining("")) + .toLowerCase(); + if (kinds.contains(Kind.FIELD)) { + out.println(" /** Field for " + name + ". */"); + out.println(" public Property " + name + ";"); + } + if (kinds.contains(Kind.GETTER)) { + out.println(" /**"); + out.println(" * Getter for " + name + "."); + out.println(" * @return a " + name); + out.println(" */"); + out.println(" public Object " + mname("get", name) + "() { return null; }"); + } + if (kinds.contains(Kind.SETTER)) { + out.println(" /**"); + out.println(" * Setter for " + name + "."); + out.println(" * @param o a " + name); + out.println(" */"); + out.println(" public void " + mname("set", name) + "(Object o) { }"); + } + if (kinds.contains(Kind.PROPERTY)) { + out.println(" /**"); + out.println(" * Property for " + name + "."); + out.println(" * @return the property for " + name); + out.println(" */"); + out.println(" public Property " + name + "Property() { return null; }"); + } + out.println(); + } + + String mname(String prefix, String base) { + return prefix + Character.toUpperCase(base.charAt(0)) + base.substring(1); + } + +} diff --git a/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java b/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java index 1c471fccb3a..85752d327e7 100644 --- a/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java +++ b/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java @@ -181,6 +181,7 @@ public class TestOptions extends JavadocTester { javadoc("-d", "out-9", "-linksource", "-javafx", + "--disable-javafx-strict-checks", "-sourcepath", testSrc, "-package", "linksource"); @@ -254,6 +255,7 @@ public class TestOptions extends JavadocTester { "-html4", "-linksource", "-javafx", + "--disable-javafx-strict-checks", "-sourcepath", testSrc, "-package", "linksource"); diff --git a/test/langtools/jdk/javadoc/doclet/testOrdering/TestOrdering.java b/test/langtools/jdk/javadoc/doclet/testOrdering/TestOrdering.java index c2728256e13..d7fe590c274 100644 --- a/test/langtools/jdk/javadoc/doclet/testOrdering/TestOrdering.java +++ b/test/langtools/jdk/javadoc/doclet/testOrdering/TestOrdering.java @@ -578,6 +578,7 @@ public class TestOrdering extends JavadocTester { void run() { tester.javadoc("-d", "out-5", "-javafx", + "--disable-javafx-strict-checks", "-sourcepath", tester.testSrc(new File(".").getPath()), "pkg5" ); diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java index 0755ee4b9f8..b9a84196175 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java @@ -43,6 +43,7 @@ public class TestOverrideMethods extends JavadocTester { javadoc("-d", "out-bad-option", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "--override-methods=nonsense", "pkg5"); @@ -55,6 +56,7 @@ public class TestOverrideMethods extends JavadocTester { javadoc("-d", "out-detail", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "--override-methods=detail", "pkg5"); @@ -66,6 +68,7 @@ public class TestOverrideMethods extends JavadocTester { javadoc("-d", "out-summary", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "--override-methods=summary", "pkg5"); diff --git a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java index 2c4de95fb0b..79dce8cbacd 100644 --- a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java +++ b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java @@ -42,6 +42,7 @@ public class TestProperty extends JavadocTester { void testArrays() { javadoc("-d", "out", "-javafx", + "--disable-javafx-strict-checks", "-sourcepath", testSrc, "pkg"); checkExit(Exit.OK); @@ -113,6 +114,7 @@ public class TestProperty extends JavadocTester { javadoc("-d", "out-html4", "-html4", "-javafx", + "--disable-javafx-strict-checks", "-sourcepath", testSrc, "pkg"); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index f0abcfb73c0..faa571826ad 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -285,6 +285,7 @@ public class TestSearch extends JavadocTester { javadoc("-d", "out-9", "-sourcepath", testSrc, "-javafx", + "--disable-javafx-strict-checks", "-package", "-use", "pkgfx", "pkg3"); diff --git a/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java b/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java new file mode 100644 index 00000000000..44f781c9089 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8025091 8198890 + * @summary Verify the presence visible members in the case of + * member hiding and overridding. + * @library /tools/lib ../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build JavadocTester toolbox.ToolBox builder.ClassBuilder + * @run main TestVisibleMembers + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import builder.AbstractBuilder; +import builder.AbstractBuilder.Comment.Kind; +import builder.ClassBuilder; +import builder.ClassBuilder.*; + +import toolbox.ToolBox; +import builder.ClassBuilder; + +public class TestVisibleMembers extends JavadocTester { + + final ToolBox tb; + public static void main(String... args) throws Exception { + TestVisibleMembers tester = new TestVisibleMembers(); + tester.runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + TestVisibleMembers() { + tb = new ToolBox(); + } + + @Test + void testChronoDiamondLeafDetail(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitChronoDiamondLeaf(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=detail", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C.html", "METHOD SUMMARY", + "boolean", "equals", "java.lang.Object", "Method equals in p.C", + "C", "with", "java.lang.Object", "obj", "Method with in p.C", + "C", "with", "java.lang.Object", "obj", "long", "lvalue", "Method with in p.C", + "METHOD DETAIL"); + checkOutput("p/C.html", false, "BImpl"); + + checkOrder("p/E.html", "METHOD SUMMARY", + "boolean", "equals", "java.lang.Object", "Method equals in p.E", + "C", "with", "java.lang.Object", "Method with in p.E", + "C", "with", "java.lang.Object", "obj", "long", "lvalue", "Method with in p.E", + "METHOD DETAIL"); + checkOutput("p/E.html", false, "EImpl"); + } + + @Test + void testChronoDiamondLeafSummary(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitChronoDiamondLeaf(srcDir); + + Path outDir = base.resolve("out-member"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=summary", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C.html", "METHOD SUMMARY", + "boolean", "equals", "java.lang.Object", "Method equals in p.C", + "C", "with", "java.lang.Object", "obj", "Method with in p.C", + "C", "with", "java.lang.Object", "obj", "long", "lvalue", "Method with in p.C", + "METHOD DETAIL"); + checkOutput("p/C.html", false, "BImpl"); + + checkOrder("p/E.html", "METHOD SUMMARY", + "boolean", "equals", "java.lang.Object", "Method equals in p.E", + "C", "with", "java.lang.Object", "Method with in p.E", + "C", "with", "java.lang.Object", "long", "lvalue", "Method with in p.E", + "METHOD DETAIL"); + checkOutput("p/E.html", false, "EImpl"); + } + + // see j.t.TemporalAdjuster + void emitChronoDiamondLeaf(Path srcDir) throws Exception { + + // Interface A + MethodBuilder mbWith1 = MethodBuilder + .parse("default Object with(Object obj) {return null;}"); + MethodBuilder mbWith2 = MethodBuilder + .parse("default Object with(Object obj, long lvalue) {return null;}"); + + new ClassBuilder(tb, "p.A") + .setModifiers("public", "interface") + .addMembers(mbWith1, mbWith2) + .write(srcDir); + + // Interface B + mbWith1.setComments("{@inheritDoc}", "@param obj an object", + "@return something"); + + mbWith2.setComments("{@inheritDoc}", "@param obj an object", + "@param lvalue an lvalue", "@return something"); + + new ClassBuilder(tb, "p.B") + .setModifiers( "public", "interface") + .setExtends("A") + .addMembers(mbWith1, mbWith2) + .write(srcDir); + + // Class BImpl + MethodBuilder mb31 = MethodBuilder.parse("C with(Object obj) {return null;}"); + MethodBuilder mb32 = MethodBuilder.parse("C with(Object obj, Long lobj) {return null;}"); + new ClassBuilder(tb, "p.BImpl") + .setModifiers( "abstract", "class") + .addImplements("B") + .addMembers(mb31, mb32) + .write(srcDir); + + // Class C + new ClassBuilder(tb, "p.C") + .setModifiers("public", "class") + .setExtends("BImpl") + .addMembers(mbWith1.setReturn("C") + .setModifiers("public") + .setComments(AbstractBuilder.Comment.Kind.AUTO)) + .addMembers(mbWith2.setReturn("C") + .setModifiers("public") + .setComments(AbstractBuilder.Comment.Kind.AUTO)) + .addMembers(MethodBuilder.parse("public boolean equals(Object obj) { return false;}")) + .write(srcDir); + + // Class EImpl + MethodBuilder mb41 = MethodBuilder.parse("C with(Object obj) {return null;}") + .setComments(Kind.NO_API_COMMENT); + MethodBuilder mb42 = MethodBuilder.parse("C with(Object obj, Long lobj) {return null;}"); + new ClassBuilder(tb, "p.EImpl") + .setModifiers( "abstract", "class") + .addImplements("B") + .addMembers(mb41, mb42) + .write(srcDir); + + // Class E + MethodBuilder mb51 = MethodBuilder.parse("public C with(Object obj) {return null;}"); + MethodBuilder mb52 = MethodBuilder.parse("public C with(Object obj, long lvalue) {return null;}"); + MethodBuilder mb53 = MethodBuilder.parse("public boolean equals(Object obj) { return false;}"); + new ClassBuilder(tb, "p.E") + .setModifiers("public", "class") + .setExtends("EImpl") + .addMembers(mb51, mb52, mb53) + .write(srcDir); + } + + @Test + void testNestedInterfaceDetail(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitNestedInterface(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=detail", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOutput("p/TA.html", false, "getTA"); + + checkOrder("p/Bar.html", + "doSomething()", + "getTA()"); + } + + @Test + void testNestedInterfaceSummary(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitNestedInterface(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=summary", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOutput("p/TA.html", false, "getTA"); + + checkOrder("p/Bar.html", + "doSomething()", + "getTA()"); + + checkOrder("p/Foo.html", + "Methods declared in", + "Bar.html", + "getTA"); + } + + // See jx.s.TransferHandler + void emitNestedInterface(Path srcDir) throws Exception { + + ClassBuilder innerI = new ClassBuilder(tb, "HasTA") + .setModifiers("interface"); + MethodBuilder interfaceMethod = MethodBuilder.parse("public TA getTa();") + .setComments(Kind.NO_API_COMMENT); + innerI.addMembers(interfaceMethod); + + new ClassBuilder(tb, "p.TA") + .setModifiers("public", "class") + .addImplements("java.io.Serializable") + .addNestedClasses(innerI) + .write(srcDir); + + new ClassBuilder(tb, "p.Foo") + .setModifiers("public", "class") + .setExtends("Bar") + .write(srcDir); + + new ClassBuilder(tb, "p.Bar") + .setModifiers("public", "abstract", "class") + .addImplements("TA.HasTA") + .addMembers( + MethodBuilder.parse("public void doSomething(){}"), + MethodBuilder.parse("public TA getTA(){return null;}") + ).write(srcDir); + } + + @Test + void testStreamsMissingLinksDetail(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitStreamsMissingLinks(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=detail", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C.html", + "METHOD DETAIL", + "public", "void", "method()", + "See Also:", + "sub()", + "sub1()"); + + checkOrder("p/ILong.html", + "METHOD DETAIL", + "default", "void", "forEach", "java.util.function.Consumer", + "java.lang.Long", "action", + "Do you see me", "#forEach(java.util.function.LongConsumer)", + "forEach(LongConsumer)", + "END OF CLASS DATA"); + + checkOrder("p/IImpl.html", + "METHOD DETAIL", + "Method sub in p.IImpl", + "Specified by:", "I.html", "II.html", + "END OF CLASS DATA"); + } + + @Test + void testStreamsMissingLinksSummary(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitStreamsMissingLinks(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=summary", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C.html", + "METHOD DETAIL", + "public", "void", "method()", "See Also:", "sub()", "I.sub1()", + "public", "void", "m", "Method in C. See", "I.length()" + ); + + checkOrder("p/ILong.html", + "METHOD DETAIL", + "default", "void", "forEach", "java.util.function.Consumer", + "java.lang.Long", "action", + "Do you see me", "QLong.html#forEach(Q)", + "QLong.forEach(LongConsumer)", + "END OF CLASS DATA"); + + checkOrder("p/IImpl.html", + "METHOD DETAIL", + "Method sub in p.IImpl", + "Specified by:", "I.html", + "END OF CLASS DATA"); + + checkUnique("p/IImpl.html", "Specified by:"); + } + + // see j.u.Spliterator + void emitStreamsMissingLinks(Path srcDir) throws Exception { + new ClassBuilder(tb, "p.I") + .setModifiers("public", "interface") + .addMembers( + MethodBuilder.parse("public I sub();"), + MethodBuilder.parse("public I sub1();"), + MethodBuilder.parse("public int length();") + ).write(srcDir); + + new ClassBuilder(tb, "p.A") + .setModifiers("abstract", "class") + .addImplements("I") + .addMembers( + MethodBuilder.parse("public I sub() {}"), + MethodBuilder.parse("public I sub1() {}"), + MethodBuilder.parse("public int length(){return 0;}") + .setComments(Kind.NO_API_COMMENT), + MethodBuilder.parse("public void m(){}") + .setComments("Method in C. See {@link #length()}.") + ).write(srcDir); + + new ClassBuilder(tb, "p.C") + .setModifiers("public", "class") + .setExtends("A").addImplements("I") + .addMembers( + MethodBuilder.parse("public I sub() {return null;}"), + MethodBuilder.parse("public I sub1() {return null;}") + .setComments(Kind.INHERIT_DOC), + MethodBuilder.parse(" public void method() {}") + .setComments("A method ", "@see #sub", "@see #sub1"), + MethodBuilder.parse("public int length(){return 1;}") + .setComments(Kind.NO_API_COMMENT) + ).write(srcDir); + + new ClassBuilder(tb, "p.II") + .setModifiers("public", "interface") + .setExtends("I") + .addMembers( + MethodBuilder.parse("default public I sub() {return null;}") + .setComments(Kind.NO_API_COMMENT) + ).write(srcDir); + + new ClassBuilder(tb, "p.IImpl") + .setModifiers("public", "class") + .addImplements("II") + .addMembers( + MethodBuilder.parse("public I sub() {return null;}") + ).write(srcDir); + + new ClassBuilder(tb, "p.QLong") + .setModifiers("public interface") + .addMembers( + MethodBuilder.parse("default void forEach(Q action) {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.ILong") + .addImports("java.util.function.*") + .setModifiers("public", "interface") + .setExtends("QLong") + .addMembers( + MethodBuilder.parse("default void forEach(LongConsumer action) {}") + .setComments(Kind.NO_API_COMMENT), + MethodBuilder.parse("default void forEach(Consumer action) {}") + .setComments("Do you see me {@link #forEach(LongConsumer)} ?") + ).write(srcDir); + } + + @Test + void testVisibleMemberTableDetail(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitVisibleMemberTable(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=detail", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C.html", + "METHOD DETAIL", + "public", "void", "m()", "Method m in p.B", + "public", "void", "n()", "Method n in p.A", + "public", "void", "o()", "Description copied from class:", ">A<", "Method o in p.A", + "public", "void", "p()", "Method p in p.B", + "END OF CLASS DATA"); + + checkOutput("p/C.html", false, + "Overrides", + "Methods declared in class p"); + + checkOrder("p/D.html", + "METHOD SUMMARY", + "void", "m", "Method m in p.D", + "void", "n", "Method n in p.D", + "void", "o", "Method o in p.D", + "void", "p", "Method p in p.D", + "CONSTRUCTOR DETAIL"); + + checkOutput("p/D.html", false, + "Description copied from class:", + "Overrides", + "Methods declared in class p"); + + checkOrder("p/E.html", + "METHOD SUMMARY", + "void", "m", "Method m in p.B", + "void", "n", "Method n in p.A", + "void", "o", "Method o in p.A", + "void", "p", "Method p in p.B", + "CONSTRUCTOR DETAIL"); + + checkOutput("p/E.html", false, + "Description copied from class:", + "Overrides", + "Methods declared in class p"); + } + + @Test + void testVisibleMemberTableSummary(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitVisibleMemberTable(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=summary", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C.html", + "METHOD SUMMARY", + "void", "m", "Method m in p.B", + "void", "n", "Method n in p.A", + "void", "o", "Method o in p.A", + "void", "p", "Method p in p.B", + "CONSTRUCTOR DETAIL"); + + checkOrder("p/C.html", + "METHOD DETAIL", + "public", "void", "m()", "Method m in p.B", + "public", "void", "n()", "Method n in p.A", + "public", "void", "o()", "Description copied from class:", ">A<", "Method o in p.A", + "public", "void", "p()", "Method p in p.B", + "END OF CLASS DATA"); + + checkOutput("p/C.html", false, + "Overrides", + "Methods declared in class p"); + + checkOrder("p/D.html", + "METHOD SUMMARY", + "void", "m", "Method m in p.D", + "void", "n", "Method n in p.D", + "void", "o", "Method o in p.D", + "void", "p", "Method p in p.D", + "CONSTRUCTOR DETAIL"); + + checkOutput("p/D.html", false, + "Description copied from class:", + "Overrides", + "Methods declared in class p"); + + checkOrder("p/E.html", + "METHOD SUMMARY", + "void", "m", "Method m in p.B", + "void", "n", "Method n in p.A", + "void", "o", "Method o in p.A", + "void", "p", "Method p in p.B", + "CONSTRUCTOR DETAIL"); + + checkOutput("p/E.html", false, + "Description copied from class:", + "Overrides", + "Methods declared in class p"); + + } + + // emit a matrix of method variants + void emitVisibleMemberTable(Path srcDir) throws Exception { + new ClassBuilder(tb, "p.A") + .setModifiers("public", "class") + .addMembers( + MethodBuilder.parse("public void m() {}"), + MethodBuilder.parse("public void n() {}"), + MethodBuilder.parse("public void o() {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.B") + .setModifiers("class") + .setExtends("A") + .addMembers( + MethodBuilder.parse("public void m() {}"), + MethodBuilder.parse("public void n() {}") + .setComments(Kind.INHERIT_DOC), + MethodBuilder.parse("public void o() {}") + .setComments(Kind.NO_API_COMMENT), + MethodBuilder.parse("public void p() {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.C") + .setModifiers("public", "class") + .setExtends("B") + .addMembers( + MethodBuilder.parse("public void m() {}") + .setComments(Kind.NO_API_COMMENT), + MethodBuilder.parse("public void n() {}") + .setComments(Kind.NO_API_COMMENT), + MethodBuilder.parse("public void o() {}") + .setComments(Kind.NO_API_COMMENT), + MethodBuilder.parse("public void p() {}") + .setComments(Kind.NO_API_COMMENT) + ).write(srcDir); + + new ClassBuilder(tb, "p.D") + .setModifiers("public", "class") + .setExtends("B") + .addMembers( + MethodBuilder.parse("public void m() {}"), + MethodBuilder.parse("public void n() {}"), + MethodBuilder.parse("public void o() {}"), + MethodBuilder.parse("public void p() {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.E") + .setModifiers("public", "class") + .setExtends("B") + .addMembers( + MethodBuilder.parse("public void m() {}") + .setComments(Kind.INHERIT_DOC), + MethodBuilder.parse("public void n() {}") + .setComments(Kind.INHERIT_DOC), + MethodBuilder.parse("public void o() {}") + .setComments(Kind.INHERIT_DOC), + MethodBuilder.parse("public void p() {}") + .setComments(Kind.INHERIT_DOC) + ).write(srcDir); + } + + @Test + void testHiddenMembersDetail(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitHiddenMembers(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=detail", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C1.html", + "FIELD SUMMARY", + "Fields inherited from interface", "I1", "field2", + "Fields inherited from interface", "I2", "field2", + "Fields inherited from interface", "I3", "field", + "METHOD SUMMARY", + "Methods inherited from interface", "I1", "method2", + "Methods inherited from interface", "I2", "method2", + "Methods inherited from interface", "I3", "method", + "CONSTRUCTOR DETAIL"); + + checkOrder("p/C2.html", + "FIELD SUMMARY", + "int", "field", "Field field in p.C2", + "Fields inherited from interface", "I1", "field2", + "Fields inherited from interface", "I2", "field2", + "METHOD SUMMARY", + "void", "method", "Method method in p.C2", + "void", "method2", "Method method2 in p.C2"); + + } + + @Test + void testHiddenMembersSummary(Path base) throws Exception { + Path srcDir = base.resolve("src"); + emitHiddenMembers(srcDir); + + Path outDir = base.resolve("out"); + javadoc("-d", outDir.toString(), + "-html5", + "--override-methods=summary", + "-sourcepath", srcDir.toString(), + "p"); + checkExit(Exit.OK); + + checkOrder("p/C1.html", + "Field Summary", + "Fields declared in interface", "I1", "field2", + "Fields declared in interface", "I2", "field2", + "Fields declared in interface", "I3", "field", + "Method Summary", + "Methods declared in interface", "I1", "method2", + "Methods declared in interface", "I2", "method2", + "Methods declared in interface", "I3", "method", + "Constructor Detail"); + + checkOrder("p/C2.html", + "Field Summary", + "int", "field", "Field field in p.C2", + "Fields declared in interface", "I1", "field2", + "Fields declared in interface", "I2", "field2", + "Method Summary", + "void", "method", "Method method in p.C2", + "void", "method2", "Method method2 in p.C2"); + + } + + void emitHiddenMembers(Path srcDir) throws Exception { + new ClassBuilder(tb, "p.I1") + .setModifiers("public", "interface") + .addMembers( + FieldBuilder.parse("public static int field = 3;"), + FieldBuilder.parse("public static int field2 = 3;"), + MethodBuilder.parse("public void method();"), + MethodBuilder.parse("public void method2();"), + MethodBuilder.parse("public static void staticMethod() {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.I2") + .setModifiers("public", "interface") + .addMembers( + FieldBuilder.parse("public static int field = 3;"), + FieldBuilder.parse("public static int field2 = 3;"), + MethodBuilder.parse("public void method();"), + MethodBuilder.parse("public void method2();"), + MethodBuilder.parse("public static void staticMethod() {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.I3") + .setExtends("I1, I2") + .setModifiers("public", "interface") + .addMembers( + FieldBuilder.parse("public static int field = 3;"), + MethodBuilder.parse("public void method();"), + MethodBuilder.parse("public static void staticMethod() {}") + ).write(srcDir); + + new ClassBuilder(tb, "p.C1") + .setModifiers("public", "abstract", "class") + .addImplements("I3") + .write(srcDir); + + new ClassBuilder(tb, "p.C2") + .setExtends("C1") + .setModifiers("public", "abstract", "class") + .addMembers( + FieldBuilder.parse("public int field;"), + MethodBuilder.parse("public void method(){}"), + MethodBuilder.parse("public void method2(){}") + ).write(srcDir); + } +} diff --git a/test/langtools/tools/lib/builder/AbstractBuilder.java b/test/langtools/tools/lib/builder/AbstractBuilder.java new file mode 100644 index 00000000000..a2e72a7cad8 --- /dev/null +++ b/test/langtools/tools/lib/builder/AbstractBuilder.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package builder; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.List; + +public abstract class AbstractBuilder { + + final String name; + + Modifiers modifiers; + Comment comments; + String cname; + + /** + * Constructs the base builder. + * @param modifiers for the class + * @param name of the element + */ + public AbstractBuilder(Modifiers modifiers, String name) { + this.modifiers = modifiers; + this.name = name; + this.comments = new Comment(Comment.Kind.AUTO); + } + + AbstractBuilder setModifiers(String... mods) { + this.modifiers = new Modifiers(mods); + return this; + } + + /** + * Sets the enclosing type's name. + * @param className the enclosing type's name + */ + void setClassName(String className) { + this.cname = className; + } + + /** + * Sets the comment type for the member. + * @param comment for the member. + * @return this builder. + */ + public AbstractBuilder setComments(Comment comment) { + this.comments = comment; + return this; + } + + /** + * Sets the comments for the member. + * @param comments for the member. + * @return this builder. + */ + public AbstractBuilder setComments(String... comments) { + this.comments = new Comment(comments); + return this; + } + + /** + * Sets a comment for the element. Typically used to set + * user's preferences whether an automatic comment is + * required or no API comment. + * + * @param kind of comment, automatic or no comment. + * @return this builder. + */ + public AbstractBuilder setComments(Comment.Kind kind) { + switch (kind) { + case NO_API_COMMENT: case AUTO: case INHERIT_DOC: + this.comments = new Comment(kind); + break; + default: + throw new IllegalArgumentException(kind + " not allowed"); + } + return this; + } + + /** + * The comment container. + */ + public static class Comment { + + /** + * The kinds of a comment. + */ + public enum Kind { + /** + * user specified + */ + USER, + /** + * no API comments + */ + NO_API_COMMENT, + /** + * inserts the javadoc tag + */ + INHERIT_DOC, + /** + * auto generate one + */ + AUTO + } + + final Kind kind; + final List comments; + + /** + * Construct an initial comment. + * + * @param kind + */ + public Comment(Kind kind) { + this.kind = kind; + comments = Collections.emptyList(); + } + + /** + * Specify a user comment. + * + * @param comments the string of API comments. + */ + public Comment(String... comments) { + kind = Kind.USER; + this.comments = comments == null + ? Collections.emptyList() + : List.of(comments); + } + + @Override + public String toString() { + ClassBuilder.OutputWriter ow = new ClassBuilder.OutputWriter(); + switch (kind) { + case USER: + comments.forEach((s) -> ow.println(" " + s)); + break; + case INHERIT_DOC: + ow.println("{@inheritDoc}"); + break; + } + return ow.toString(); + } + } + + /** + * The modifier representation for an element. + */ + public static class Modifiers { + List modifiers; + + /** + * Constructs a modifier container. + * @param modifiers for an element. + */ + public Modifiers(String... modifiers) { + this.modifiers = List.of(modifiers); + } + + /** + * Constructs a modifier container. + * @param modifiers a list of modifier strings. + */ + public Modifiers(List modifiers) { + this.modifiers = modifiers; + } + + /** + * Sets the modifiers for this element. + * @param modifiers + */ + public void setModifiers(String... modifiers) { + this.modifiers = List.of(modifiers); + } + + /** + * Sets the modifiers for this element. + * @param modifiers + */ + public void setModifiers(List modifiers) { + this.modifiers = modifiers; + } + + @Override + public String toString() { + OutputWriter ow = new OutputWriter(); + modifiers.forEach(i -> ow.print(i + " ")); + return ow.toString(); + } + } + + /** + * The output writer. + */ + public static class OutputWriter { + private final StringWriter sw = new StringWriter(); + private final PrintWriter pw = new PrintWriter(sw); + + @Override + public String toString() { + return sw.getBuffer().toString(); + } + + /** + * Prints a string without NL. + * @param s the string to print. + */ + public void print(String s) { + pw.print(s); + } + + /** + * Prints a string with a NL. + * @param s the string to print. + */ + public void println(String s) { + pw.println(s); + } + } + + /** + * A container to encapsulate a pair of values. + */ + public static class Pair { + final String first; + final String second; + + public Pair(String first, String second) { + this.first = first; + this.second = second; + } + } +} diff --git a/test/langtools/tools/lib/builder/ClassBuilder.java b/test/langtools/tools/lib/builder/ClassBuilder.java new file mode 100644 index 00000000000..51acdd53d5b --- /dev/null +++ b/test/langtools/tools/lib/builder/ClassBuilder.java @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package builder; + +import toolbox.ToolBox; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Builder for type declarations. + * Note: this implementation does not support everything and is not + * exhaustive. + */ +public class ClassBuilder extends AbstractBuilder { + + private final ToolBox tb; + private final String fqn; + private final String clsname; + private final String typeParameter; + + private String pkg; + private final List imports; + + private String extendsType; + private final List implementsTypes; + private final List members; + private final List inners; + private final List nested; + + + final static Pattern CLASS_RE = Pattern.compile("(.*)(<.*>)"); + + /** + * Creates a class builder. + * @param tb the toolbox reference + * @param name the name of the type + */ + public ClassBuilder(ToolBox tb, String name) { + super(new Modifiers(), name); + this.tb = tb; + + Matcher m = CLASS_RE.matcher(name); + if (m.matches()) { + fqn = m.group(1); + typeParameter = m.group(2); + } else { + fqn = name; + typeParameter = null; + } + if (fqn.contains(".")) { + this.pkg = name.substring(0, fqn.lastIndexOf('.')); + clsname = fqn.substring(fqn.lastIndexOf('.') + 1); + } else { + clsname = fqn; + } + imports = new ArrayList<>(); + implementsTypes = new ArrayList<>(); + members = new ArrayList<>(); + nested = new ArrayList<>(); + inners = new ArrayList<>(); + } + + /** + * Adds an import(s). + * @param i the import type. + * @return this builder. + */ + public ClassBuilder addImports(String i) { + imports.add(i); + return this; + } + + /** + * Sets the modifiers for this builder. + * @param modifiers the modifiers + * @return this builder + */ + public ClassBuilder setModifiers(String... modifiers) { + this.modifiers.setModifiers(modifiers); + return this; + } + + /** + * Sets the enclosing type's name. + * + * @param className the enclosing type's name + */ + @Override + void setClassName(String className) { + cname = className; + } + + /** + * Sets a comment for the element. + * + * @param comments for the element + * @return this builder. + */ + @Override + public ClassBuilder setComments(String... comments) { + super.setComments(comments); + return this; + } + + /** + * Sets a comment for the element. Typically used to set + * the user's preferences whether an automatic comment is + * required or no API comment. + * + * @param kind of comment, automatic or no comment. + * @return this builder. + */ + @Override + public ClassBuilder setComments(Comment.Kind kind) { + super.setComments(kind); + return this; + } + + /** + * Set the super-type of the type. + * @param name of the super type. + * @return this builder. + */ + public ClassBuilder setExtends(String name) { + extendsType = name; + return this; + } + + /** + * Adds an implements declaration(s). + * @param names the interfaces + * @return this builder. + */ + public ClassBuilder addImplements(String... names) { + implementsTypes.addAll(List.of(names)); + return this; + } + + /** + * Adds a member(s) to the class declaration. + * @param mbs the member builder(s) representing member(s). + * @return this builder + */ + public ClassBuilder addMembers(MemberBuilder... mbs) { + for (MemberBuilder mb : mbs) { + members.add(mb); + mb.setClassName(fqn); + } + return this; + } + + /** + * Adds nested-classes, to an outer class to an outer builder. + * @param cbs class builder(s) of the nested classes. + * @return this builder. + */ + public ClassBuilder addNestedClasses(ClassBuilder... cbs) { + Stream.of(cbs).forEach(cb -> { + nested.add(cb); + cb.setClassName(fqn); + }); + return this; + } + + /** + * Adds inner-classes, to an an outer class builder. + * @param cbs class builder(s) of the inner classes. + * @return this builder. + */ + public ClassBuilder addInnerClasses(ClassBuilder... cbs) { + Stream.of(cbs).forEach(cb -> { + inners.add(cb); + cb.setClassName(fqn); + }); + return this; + } + + @Override + public String toString() { + OutputWriter ow = new OutputWriter(); + if (pkg != null) + ow.println("package " + pkg + ";"); + imports.forEach(i -> ow.println("import " + i + ";")); + switch (comments.kind) { + case AUTO: + ow.println("/** Class " + fqn + " */"); + break; + case USER: + ow.println("/** "); + comments.comments.forEach(c -> ow.println(" * " + c)); + ow.println(" */"); + break; + case NO_API_COMMENT: + ow.println("// NO_API_COMMENT"); + break; + } + ow.print(modifiers.toString()); + ow.print(clsname); + if (typeParameter != null) { + ow.print(typeParameter + " "); + } else { + ow.print(" "); + } + if (extendsType != null && !extendsType.isEmpty()) { + ow.print("extends " + extendsType + " "); + } + if (!implementsTypes.isEmpty()) { + ow.print("implements "); + + ListIterator iter = implementsTypes.listIterator(); + while (iter.hasNext()) { + String s = iter.next() ; + ow.print(s); + if (iter.hasNext()) + ow.print(", "); + } + } + ow.print("{"); + if (!nested.isEmpty()) { + ow.println(""); + nested.forEach(m -> ow.println(m.toString())); + } + + if (!members.isEmpty()) { + ow.println(""); + members.forEach(m -> ow.println(m.toString())); + } + + ow.println("}"); + if (!inners.isEmpty()) { + ow.println(" {"); + inners.forEach(m -> ow.println(m.toString())); + ow.println("}"); + } + return ow.toString(); + } + + /** + * Writes out the java source for a type element. Package directories + * will be created as needed as inferred by the type name. + * @param srcDir the top level source directory. + * @throws IOException if an error occurs. + */ + public void write(Path srcDir) throws IOException { + Files.createDirectories(srcDir); + Path outDir = srcDir; + if (pkg != null && !pkg.isEmpty()) { + String pdir = pkg.replace(".", "/"); + outDir = Paths.get(srcDir.toString(), pdir); + Files.createDirectories(outDir); + } + Path filePath = Paths.get(outDir.toString(), clsname + ".java"); + tb.writeFile(filePath, this.toString()); + } + + /** + * The member builder, this is the base class for all types of members. + */ + public static abstract class MemberBuilder extends AbstractBuilder { + public MemberBuilder(Modifiers modifiers, String name) { + super(modifiers, name); + } + + /** + * Sets the enclosing type's name. + * @param className the enclosing type's name + */ + @Override + void setClassName(String className) { + cname = className; + } + + /** + * Sets a comment for the element. + * + * @param comments for any element + * @return this builder. + */ + @Override + public MemberBuilder setComments(String... comments) { + super.setComments(comments); + return this; + } + + /** + * Sets a comment for the element. Typically used to set user's + * preferences whether an automatic comment is required or no API + * comment. + * + * @param kind of comment, automatic or no comment. + * @return this builder. + */ + @Override + public MemberBuilder setComments(Comment.Kind kind) { + super.setComments(kind); + return this; + } + + /** + * Sets a new modifier. + * + * @param modifiers + * @return this builder. + */ + @Override + public MemberBuilder setModifiers(String... modifiers) { + super.setModifiers(modifiers); + return this; + } + } + + /** + * The field builder. + */ + public static class FieldBuilder extends MemberBuilder { + private String fieldType; + private String value; + + private static final Pattern FIELD_RE = Pattern.compile("(.*)(\\s*=\\s*)(.*)(;)"); + + /** + * Constructs a field with the modifiers and name of the field. + * The builder by default is configured to auto generate the + * comments for the field. + * @param name of the field + */ + public FieldBuilder(String name) { + super(new Modifiers(), name); + this.comments = new Comment(Comment.Kind.AUTO); + } + + /** + * Returns a field builder by parsing the string. + * ex: public static String myPlayingField; + * @param fieldString describing the field. + * @return a field builder. + */ + public static FieldBuilder parse(String fieldString) { + String prefix; + String value = null; + Matcher m = FIELD_RE.matcher(fieldString); + if (m.matches()) { + prefix = m.group(1).trim(); + value = m.group(3).trim(); + } else { + int end = fieldString.lastIndexOf(';') > 0 + ? fieldString.lastIndexOf(';') + : fieldString.length(); + prefix = fieldString.substring(0, end).trim(); + } + List list = Stream.of(prefix.split(" ")) + .filter(s -> !s.isEmpty()).collect(Collectors.toList()); + if (list.size() < 2) { + throw new IllegalArgumentException("incorrect field string: " + + fieldString); + } + String name = list.get(list.size() - 1); + String fieldType = list.get(list.size() - 2); + + FieldBuilder fb = new FieldBuilder(name); + fb.modifiers.setModifiers(list.subList(0, list.size() - 2)); + fb.setFieldType(fieldType); + if (value != null) + fb.setValue(value); + + return fb; + } + + /** + * Sets the modifiers for this builder. + * + * @param mods + * @return this builder + */ + public FieldBuilder setModifiers(String mods) { + this.modifiers.setModifiers(mods); + return this; + } + + /** + * Sets the type of the field. + * @param fieldType the name of the type. + * @return this field builder. + */ + public FieldBuilder setFieldType(String fieldType) { + this.fieldType = fieldType; + return this; + } + + public FieldBuilder setValue(String value) { + this.value = value; + return this; + } + + @Override + public String toString() { + String indent = " "; + OutputWriter ow = new OutputWriter(); + switch (comments.kind) { + case AUTO: + ow.println(indent + "/** Field " + + super.name + " in " + super.cname + " */"); + break; + case INHERIT_DOC: case USER: + ow.println(indent + "/** " + + comments.toString() + " */"); + break; + case NO_API_COMMENT: + ow.println(indent + "// NO_API_COMMENT"); + break; + } + ow.print(indent + super.modifiers.toString() + " "); + ow.print(fieldType + " "); + ow.print(super.name); + if (value != null) { + ow.print(" = " + value); + } + ow.println(";"); + return ow.toString(); + } + } + + /** + * The method builder. + */ + public static class MethodBuilder extends MemberBuilder { + + private final List params; + + private String returnType; + private List body; + + final static Pattern METHOD_RE = Pattern.compile("(.*)(\\()(.*)(\\))(.*)"); + + /** + * Constructs a method builder. The builder by default is configured + * to auto generate the comments for this method. + * @param name of the method. + */ + public MethodBuilder(String name) { + super(new Modifiers(), name); + comments = new Comment(Comment.Kind.AUTO); + params = new ArrayList<>(); + body = null; + } + + /** + * Returns a method builder by parsing a string which + * describes a method. + * @param methodString the method description. + * @return a method builder. + */ + public static MethodBuilder parse(String methodString) { + Matcher m = METHOD_RE.matcher(methodString); + if (!m.matches()) + throw new IllegalArgumentException("string does not match: " + + methodString); + String prefix = m.group(1); + String params = m.group(3); + String suffix = m.group(5).trim(); + + if (prefix.length() < 2) { + throw new IllegalArgumentException("incorrect method string: " + + methodString); + } + + String[] pa = prefix.split(" "); + List list = List.of(pa); + String name = list.get(list.size() - 1); + String returnType = list.get(list.size() - 2); + + MethodBuilder mb = new MethodBuilder(name); + mb.modifiers.setModifiers(list.subList(0, list.size() - 2)); + mb.setReturn(returnType); + + pa = params.split(","); + Stream.of(pa).forEach(p -> { + p = p.trim(); + if (!p.isEmpty()) + mb.addParameter(p); + }); + if (!suffix.isEmpty() || suffix.length() > 1) { + mb.setBody(suffix); + } + return mb; + } + + /** + * Sets the modifiers for this builder. + * + * @param modifiers + * @return this builder + */ + public MethodBuilder setModifiers(String modifiers) { + this.modifiers.setModifiers(modifiers); + return this; + } + + @Override + public MethodBuilder setComments(String... comments) { + super.setComments(comments); + return this; + } + + @Override + public MethodBuilder setComments(Comment.Kind kind) { + super.setComments(kind); + return this; + } + + /** + * Sets a return type for a method. + * @param returnType the return type. + * @return this method builder. + */ + public MethodBuilder setReturn(String returnType) { + this.returnType = returnType; + return this; + } + + /** + * Adds a parameter(s) to the method method builder. + * @param params a pair consisting of type and parameter name. + * @return this method builder. + */ + public MethodBuilder addParameters(Pair... params) { + this.params.addAll(List.of(params)); + return this; + } + + /** + * Adds a parameter to the method method builder. + * @param type the type of parameter. + * @param name the parameter name. + * @return this method builder. + */ + public MethodBuilder addParameter(String type, String name) { + this.params.add(new Pair(type, name)); + return this; + } + + /** + * Adds a parameter to the method builder, by parsing the string. + * @param s the parameter description such as "Double voltage" + * @return this method builder. + */ + public MethodBuilder addParameter(String s) { + String[] p = s.trim().split(" "); + return addParameter(p[0], p[p.length - 1]); + } + + /** + * Sets the body of the method, described by the string. + * Such as "{", "double i = v/r;", "return i;", "}" + * @param body of the methods + * @return + */ + public MethodBuilder setBody(String... body) { + if (body == null) { + this.body = null; + } else { + this.body = new ArrayList<>(); + this.body.addAll(List.of(body)); + } + return this; + } + + @Override + public String toString() { + OutputWriter ow = new OutputWriter(); + String indent = " "; + switch (comments.kind) { + case AUTO: + ow.println(indent + "/** Method " + super.name + " in " + super.cname); + if (!params.isEmpty()) + params.forEach(p -> ow.println(indent + " * @param " + p.second + " a param")); + if (returnType != null && !returnType.isEmpty() && !returnType.contains("void")) + ow.println(indent + " * @return returns something"); + ow.println(indent + " */"); + break; + case INHERIT_DOC: case USER: + ow.println(indent + "/** " + comments.toString() + " */"); + break; + case NO_API_COMMENT: + ow.println(indent + "// NO_API_COMMENT"); + break; + } + + ow.print(indent + super.modifiers.toString() + " "); + ow.print(returnType + " "); + ow.print(super.name + "("); + if (!params.isEmpty()) { + ListIterator iter = params.listIterator(); + while (iter.hasNext()) { + Pair p = iter.next(); + ow.print(p.first + " " + p.second); + if (iter.hasNext()) + ow.print(", "); + } + } + ow.print(")"); + if (body == null) { + ow.println(";"); + } else { + body.forEach(ow::println); + } + return ow.toString(); + } + } + +//A sample, to test with an IDE. +// public static void main(String... args) throws IOException { +// ClassBuilder cb = new ClassBuilder(new ToolBox(), "foo.bar.Test"); +// cb.addModifiers("public", "abstract", "static") +// .addImports("java.io").addImports("java.nio") +// .setComments("A comment") +// .addImplements("Serialization", "Something") +// .setExtends("java.lang.Object") +// .addMembers( +// FieldBuilder.parse("public int xxx;"), +// FieldBuilder.parse("public int yyy = 10;"), +// MethodBuilder.parse("public static void main(A a, B b, C c);") +// .setComments("CC"), +// MethodBuilder.parse("void foo(){//do something}") +// +// ); +// ClassBuilder ic = new ClassBuilder(new ToolBox(), "IC"); +// cb.addModifiers( "interface"); +// cb.addNestedClasses(ic); +// System.out.println(cb.toString()); +// cb.write(Paths.get("src-out")); +// } +} From 780696c2a36937dc7947df579e130385a5988e1b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 24 Apr 2018 20:25:48 -0700 Subject: [PATCH 035/102] 8202062: Put FileChannel and FileOutpuStream variants of AtomicAppend on problem list Reviewed-by: lancea --- test/jdk/ProblemList.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 40c99a5fe12..a533e8bb04c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -510,8 +510,10 @@ java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8081652 generic- # jdk_io +java/io/FileOutputStream/AtomicAppend.java 8202062 macosx-all java/io/pathNames/GeneralWin32.java 8180264 windows-all + ############################################################################ # jdk_management @@ -545,10 +547,12 @@ java/net/DatagramSocket/SendDatagramToBadAddress.java 7143960 macosx-a java/nio/Buffer/EqualsCompareTest.java 8193917 solaris-all -java/nio/channels/Selector/Wakeup.java 6963118 windows-all - java/nio/channels/DatagramChannel/ChangingAddress.java 7141822 macosx-all +java/nio/channels/FileChannel/AtomicAppend.java 8202062 macosx-all + +java/nio/channels/Selector/Wakeup.java 6963118 windows-all + java/nio/file/WatchService/Basic.java 7158947 solaris-all Solaris 11 java/nio/file/WatchService/MayFlies.java 7158947 solaris-all Solaris 11 java/nio/file/WatchService/LotsOfCancels.java 8188039 solaris-all Solaris 11 From 2dbc9735ac409e938f28330f77335f4be1983b9f Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Tue, 24 Apr 2018 21:40:10 -0700 Subject: [PATCH 036/102] 8202169: Reduce ctw_2 duration by parallelizing CtwRunner invocations Reviewed-by: kvn, iignatyev --- test/hotspot/jtreg/TEST.groups | 4 +- .../applications/ctw/modules/java_base.java | 6 +- .../applications/ctw/modules/java_base_2.java | 38 +++++++++ .../ctw/modules/java_desktop.java | 6 +- .../ctw/modules/java_desktop_2.java | 38 +++++++++ .../src/sun/hotspot/tools/ctw/CtwRunner.java | 82 ++++++++++++++++--- 6 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 test/hotspot/jtreg/applications/ctw/modules/java_base_2.java create mode 100644 test/hotspot/jtreg/applications/ctw/modules/java_desktop_2.java diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 5cd46140424..19c5262a97c 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -142,7 +142,9 @@ ctw_1 = \ ctw_2 = \ applications/ctw/modules/java_base.java \ - applications/ctw/modules/java_desktop.java + applications/ctw/modules/java_base_2.java \ + applications/ctw/modules/java_desktop.java \ + applications/ctw/modules/java_desktop_2.java ctw_3 = \ applications/ctw/modules/javafx_graphics.java \ diff --git a/test/hotspot/jtreg/applications/ctw/modules/java_base.java b/test/hotspot/jtreg/applications/ctw/modules/java_base.java index d332fcbc201..981369d0547 100644 --- a/test/hotspot/jtreg/applications/ctw/modules/java_base.java +++ b/test/hotspot/jtreg/applications/ctw/modules/java_base.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @summary run CTW for all classes from java.base module + * @summary run CTW for some classes from java.base module * * @library /test/lib / /testlibrary/ctw/src * @modules java.base/jdk.internal.jimage @@ -34,5 +34,5 @@ * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:java.base + * @run main/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:java.base 0% 50% */ diff --git a/test/hotspot/jtreg/applications/ctw/modules/java_base_2.java b/test/hotspot/jtreg/applications/ctw/modules/java_base_2.java new file mode 100644 index 00000000000..d462179d5fe --- /dev/null +++ b/test/hotspot/jtreg/applications/ctw/modules/java_base_2.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary run CTW for some classes from java.base module + * + * @library /test/lib / /testlibrary/ctw/src + * @modules java.base/jdk.internal.jimage + * java.base/jdk.internal.misc + * java.base/jdk.internal.reflect + * @modules java.base + * + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:java.base 50% 100% + */ diff --git a/test/hotspot/jtreg/applications/ctw/modules/java_desktop.java b/test/hotspot/jtreg/applications/ctw/modules/java_desktop.java index 6c38d106f9e..1bac2f614fd 100644 --- a/test/hotspot/jtreg/applications/ctw/modules/java_desktop.java +++ b/test/hotspot/jtreg/applications/ctw/modules/java_desktop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @summary run CTW for all classes from java.desktop module + * @summary run CTW for some classes from java.desktop module * * @library /test/lib / /testlibrary/ctw/src * @modules java.base/jdk.internal.jimage @@ -34,5 +34,5 @@ * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:java.desktop + * @run main/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:java.desktop 0% 50% */ diff --git a/test/hotspot/jtreg/applications/ctw/modules/java_desktop_2.java b/test/hotspot/jtreg/applications/ctw/modules/java_desktop_2.java new file mode 100644 index 00000000000..7c8d98bfcaa --- /dev/null +++ b/test/hotspot/jtreg/applications/ctw/modules/java_desktop_2.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary run CTW for some classes from java.desktop module + * + * @library /test/lib / /testlibrary/ctw/src + * @modules java.base/jdk.internal.jimage + * java.base/jdk.internal.misc + * java.base/jdk.internal.reflect + * @modules java.desktop + * + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/timeout=7200 sun.hotspot.tools.ctw.CtwRunner modules:java.desktop 50% 100% + */ diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index cdc8efaedfb..4b4a02a56ad 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,11 +52,17 @@ public class CtwRunner { private static final Predicate IS_CLASS_LINE = Pattern.compile( "^\\[\\d+\\]\\s*\\S+\\s*$").asPredicate(); + private static final String USAGE = "Usage: CtwRunner [start[%] stop[%]]"; + public static void main(String[] args) throws Exception { - if (args.length != 1) { - throw new Error("Usage: "); + CtwRunner runner; + switch (args.length) { + case 1: runner = new CtwRunner(args[0]); break; + case 3: runner = new CtwRunner(args[0], args[1], args[2]); break; + default: throw new Error(USAGE); } - new CtwRunner(args[0]).run(); + + runner.run(); } private final List errors; @@ -64,7 +70,10 @@ public class CtwRunner { private final Path targetPath; private final String targetName; - private CtwRunner(String target) { + private final int start, stop; + private final boolean isStartStopPercentage; + + private CtwRunner(String target, String start, String stop) { if (target.startsWith("modules")) { targetPath = Paths .get(Utils.TEST_JDK) @@ -82,8 +91,29 @@ public class CtwRunner { } this.target = target; errors = new ArrayList<>(); + + if (start.endsWith("%") && stop.endsWith("%")) { + int startPercentage = Integer.parseInt(start.substring(0, start.length() - 1));; + int stopPercentage = Integer.parseInt(stop.substring(0, stop.length() - 1)); + if (startPercentage < 0 || startPercentage > 100 || + stopPercentage < 0 || stopPercentage > 100) { + throw new Error(USAGE); + } + this.start = startPercentage; + this.stop = stopPercentage; + this.isStartStopPercentage = true; + } else if (!start.endsWith("%") && !stop.endsWith("%")) { + this.start = Integer.parseInt(start); + this.stop = Integer.parseInt(stop); + this.isStartStopPercentage = false; + } else { + throw new Error(USAGE); + } } + private CtwRunner(String target) { + this(target, "0%", "100%"); + } private void run() { startCtwforAllClasses(); @@ -105,15 +135,44 @@ public class CtwRunner { } } + private long start(long totalClassCount) { + if (isStartStopPercentage) { + return totalClassCount * start / 100; + } else if (start > totalClassCount) { + System.err.println("WARNING: start [" + start + "] > totalClassCount [" + totalClassCount + "]"); + return totalClassCount; + } else { + return start; + } + } + + private long stop(long totalClassCount) { + if (isStartStopPercentage) { + return totalClassCount * stop / 100; + } else if (stop > totalClassCount) { + System.err.println("WARNING: stop [" + start + "] > totalClassCount [" + totalClassCount + "]"); + return totalClassCount; + } else { + return stop; + } + } private void startCtwforAllClasses() { - long classStart = 0L; - long classCount = classCount(); + long totalClassCount = classCount(); + + long classStart = start(totalClassCount); + long classStop = stop(totalClassCount); + + long classCount = classStop - classStart; Asserts.assertGreaterThan(classCount, 0L, target + "(at " + targetPath + ") does not have any classes"); + + System.out.printf("Compiling %d classes (of %d total classes) starting at %d and ending at %d\n", + classCount, totalClassCount, classStart, classStop); + boolean done = false; while (!done) { - String[] cmd = cmd(classStart); + String[] cmd = cmd(classStart, classStop); try { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( /* addTestVmAndJavaOptions = */ true, @@ -138,11 +197,11 @@ public class CtwRunner { Pair lastClass = getLastClass(out); if (exitCode == 0) { long lastIndex = lastClass == null ? -1 : lastClass.second; - if (lastIndex != classCount) { + if (lastIndex != classStop) { errors.add(new Error(phase + ": Unexpected zero exit code" + "before finishing all compilations." + " lastClass[" + lastIndex - + "] != classCount[" + classCount + "]")); + + "] != classStop[" + classStop + "]")); } else { System.out.println("Executed CTW for all " + classCount + " classes in " + target + "(at " + targetPath + ")"); @@ -197,7 +256,7 @@ public class CtwRunner { return null; } - private String[] cmd(long classStart) { + private String[] cmd(long classStart, long classStop) { String phase = phaseName(classStart); return new String[] { "-Xbatch", @@ -206,6 +265,7 @@ public class CtwRunner { "-XX:+UnlockDiagnosticVMOptions", // define phase start "-DCompileTheWorldStartAt=" + classStart, + "-DCompileTheWorldStopAt=" + classStop, // CTW library uses WhiteBox API "-XX:+WhiteBoxAPI", "-Xbootclasspath/a:.", // export jdk.internal packages used by CTW library From a3ed7dd7d68f2e05066af06e6c7747dea0860b1c Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gopularam Date: Wed, 25 Apr 2018 12:29:48 +0530 Subject: [PATCH 037/102] 8144806: sun/security/tools/keytool/standard.sh fails intermittently at deleting x.jks Reviewed-by: weijun --- .../security/tools/keytool/KeyToolTest.java | 10 ++++++---- .../sun/security/tools/keytool/autotest.sh | 20 +++++++++++++------ .../sun/security/tools/keytool/standard.sh | 16 ++++++++++++--- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/test/jdk/sun/security/tools/keytool/KeyToolTest.java b/test/jdk/sun/security/tools/keytool/KeyToolTest.java index 4a58232a27f..0b57875fe6c 100644 --- a/test/jdk/sun/security/tools/keytool/KeyToolTest.java +++ b/test/jdk/sun/security/tools/keytool/KeyToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,7 @@ import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.util.*; import java.security.cert.X509Certificate; +import jdk.test.lib.util.FileUtils; import sun.security.util.ObjectIdentifier; public class KeyToolTest { @@ -118,9 +119,10 @@ public class KeyToolTest { if (debug) { System.err.println("Removing " + filename); } - new File(filename).delete(); - if (new File(filename).exists()) { - throw new RuntimeException("Error deleting " + filename); + try{ + FileUtils.deleteFileIfExistsWithRetry(Paths.get(filename)); + }catch(IOException e) { + throw new RuntimeException("Error deleting " + filename, e); } } diff --git a/test/jdk/sun/security/tools/keytool/autotest.sh b/test/jdk/sun/security/tools/keytool/autotest.sh index b97310ecc64..e6261377ea1 100644 --- a/test/jdk/sun/security/tools/keytool/autotest.sh +++ b/test/jdk/sun/security/tools/keytool/autotest.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,9 @@ # @test # @summary (almost) all keytool behaviors # @author Weijun Wang -# +# @library /test/lib +# @build jdk.test.lib.util.FileUtils +# @run shell/timeout=600 autotest.sh # This test is only executed on several platforms # # set a few environment variables so that the shell-script can run stand-alone @@ -92,6 +94,14 @@ case "$OS" in exit 0; ;; esac +case "$OS" in + Windows_* | CYGWIN* ) + PS=";" + ;; + * ) + PS=":" + ;; +esac if [ "$LIBNAME" = "" ]; then echo "Cannot find libsoftokn3.so" @@ -103,8 +113,7 @@ echo "Using NSS lib at $LIBNAME" EXTRAOPTS="--add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED \ --add-exports java.base/sun.security.util=ALL-UNNAMED \ --add-exports java.base/sun.security.x509=ALL-UNNAMED" - -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file \ +${COMPILEJAVA}${FS}bin${FS}javac -classpath ${TESTCLASSPATH} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file \ ${TESTSRC}${FS}KeyToolTest.java || exit 10 NSS=${TESTSRC}${FS}..${FS}..${FS}pkcs11${FS}nss @@ -116,8 +125,7 @@ cp ${NSS}${FS}db${FS}secmod.db . chmod u+w key3.db chmod u+w cert8.db - -echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -Dnss \ +echo | ${TESTJAVA}${FS}bin${FS}java -classpath .${PS}${TESTCLASSPATH} ${TESTVMOPTS} ${EXTRAOPTS} -Dnss \ -Dnss.lib=${LIBNAME} \ KeyToolTest status=$? diff --git a/test/jdk/sun/security/tools/keytool/standard.sh b/test/jdk/sun/security/tools/keytool/standard.sh index 38fadb8c495..4072b1c5917 100644 --- a/test/jdk/sun/security/tools/keytool/standard.sh +++ b/test/jdk/sun/security/tools/keytool/standard.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ # @test # @summary (almost) all keytool behaviors # @author Weijun Wang +# @library /test/lib +# @build jdk.test.lib.util.FileUtils # @run shell/timeout=600 standard.sh # @key intermittent @@ -57,14 +59,22 @@ case "$OS" in exit 1; ;; esac +case "$OS" in + Windows_* | CYGWIN* ) + PS=";" + ;; + * ) + PS=":" + ;; +esac EXTRAOPTS="--add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED \ --add-exports java.base/sun.security.util=ALL-UNNAMED \ --add-exports java.base/sun.security.x509=ALL-UNNAMED" -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10 +${COMPILEJAVA}${FS}bin${FS}javac -classpath ${TESTCLASSPATH} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10 -echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -Dfile KeyToolTest +echo | ${TESTJAVA}${FS}bin${FS}java -classpath .${PS}${TESTCLASSPATH} ${TESTVMOPTS} ${EXTRAOPTS} -Dfile KeyToolTest status=$? exit $status From e836d6ec10b685ebf1a28c75080b27f03e0e0a8b Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gopularam Date: Wed, 25 Apr 2018 12:39:05 +0530 Subject: [PATCH 038/102] 8196540: [Testbug] java/security/AccessController/DoPrivAccompliceTest.java doesn't handle unrelated warnings Reviewed-by: mullan --- .../DoPrivAccompliceTest.java | 4 +- .../jdk/test/lib/process/OutputAnalyzer.java | 978 +++++++++--------- 2 files changed, 498 insertions(+), 484 deletions(-) diff --git a/test/jdk/java/security/AccessController/DoPrivAccompliceTest.java b/test/jdk/java/security/AccessController/DoPrivAccompliceTest.java index 711c3030dde..265e52ae981 100644 --- a/test/jdk/java/security/AccessController/DoPrivAccompliceTest.java +++ b/test/jdk/java/security/AccessController/DoPrivAccompliceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ public class DoPrivAccompliceTest { ProcessTools.executeTestJava(commands) .shouldHaveExitValue(0) .shouldContain(userName) - .stderrShouldBeEmpty(); + .stderrShouldBeEmptyIgnoreVMWarnings(); createPolicyFile(jarFile2, policy); System.out.println("Created policy for " + jarFile2); diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java index f60520ff43f..6da75e8da5f 100644 --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,511 +33,525 @@ import java.util.regex.Pattern; public final class OutputAnalyzer { - private final String stdout; - private final String stderr; - private final int exitValue; - - /** - * Create an OutputAnalyzer, a utility class for verifying output and exit - * value from a Process - * - * @param process Process to analyze - * @throws IOException If an I/O error occurs. - */ - public OutputAnalyzer(Process process) throws IOException { - OutputBuffer output = ProcessTools.getOutput(process); - exitValue = process.exitValue(); - this.stdout = output.getStdout(); - this.stderr = output.getStderr(); - } - - /** - * Create an OutputAnalyzer, a utility class for verifying output - * - * @param buf String buffer to analyze - */ - public OutputAnalyzer(String buf) { - this(buf, buf); - } - - /** - * Create an OutputAnalyzer, a utility class for verifying output - * - * @param stdout stdout buffer to analyze - * @param stderr stderr buffer to analyze - */ - public OutputAnalyzer(String stdout, String stderr) { - this.stdout = stdout; - this.stderr = stderr; - exitValue = -1; - } - - /** - * Verify that the stdout contents of output buffer is empty - * - * @throws RuntimeException - * If stdout was not empty - */ - public void stdoutShouldBeEmpty() { - if (!getStdout().isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stdout was not empty"); - } - } - - /** - * Verify that the stderr contents of output buffer is empty - * - * @throws RuntimeException - * If stderr was not empty - */ - public void stderrShouldBeEmpty() { - if (!getStderr().isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stderr was not empty"); - } - } - - /** - * Verify that the stdout contents of output buffer is not empty - * - * @throws RuntimeException - * If stdout was empty - */ - public void stdoutShouldNotBeEmpty() { - if (getStdout().isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stdout was empty"); - } - } - - /** - * Verify that the stderr contents of output buffer is not empty - * - * @throws RuntimeException - * If stderr was empty - */ - public void stderrShouldNotBeEmpty() { - if (getStderr().isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stderr was empty"); - } - } + private final String stdout; + private final String stderr; + private final int exitValue; /** - * Verify that the stdout and stderr contents of output buffer contains the string - * - * @param expectedString String that buffer should contain - * @throws RuntimeException If the string was not found - */ - public OutputAnalyzer shouldContain(String expectedString) { - if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n"); + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process + * + * @param process Process to analyze + * @throws IOException If an I/O error occurs. + */ + public OutputAnalyzer(Process process) throws IOException { + OutputBuffer output = ProcessTools.getOutput(process); + exitValue = process.exitValue(); + this.stdout = output.getStdout(); + this.stderr = output.getStderr(); } - return this; - } - /** - * Verify that the stdout contents of output buffer contains the string - * - * @param expectedString String that buffer should contain - * @throws RuntimeException If the string was not found - */ - public OutputAnalyzer stdoutShouldContain(String expectedString) { - if (!stdout.contains(expectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + expectedString + "' missing from stdout \n"); + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param buf String buffer to analyze + */ + public OutputAnalyzer(String buf) { + this(buf, buf); } - return this; - } - /** - * Verify that the stderr contents of output buffer contains the string - * - * @param expectedString String that buffer should contain - * @throws RuntimeException If the string was not found - */ - public OutputAnalyzer stderrShouldContain(String expectedString) { - if (!stderr.contains(expectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + expectedString + "' missing from stderr \n"); + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout stdout buffer to analyze + * @param stderr stderr buffer to analyze + */ + public OutputAnalyzer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; } - return this; - } - /** - * Verify that the stdout and stderr contents of output buffer does not contain the string - * - * @param expectedString String that the buffer should not contain - * @throws RuntimeException If the string was found - */ - public OutputAnalyzer shouldNotContain(String notExpectedString) { - if (stdout.contains(notExpectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + /** + * Verify that the stdout contents of output buffer is empty + * + * @throws RuntimeException + * If stdout was not empty + */ + public void stdoutShouldBeEmpty() { + if (!getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was not empty"); + } } - if (stderr.contains(notExpectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + + /** + * Verify that the stderr contents of output buffer is empty + * + * @throws RuntimeException + * If stderr was not empty + */ + public void stderrShouldBeEmpty() { + if (!getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } } - return this; - } - /** - * Verify that the stdout and stderr contents of output buffer are empty - * - * @throws RuntimeException If the stdout and stderr are not empty - */ - public OutputAnalyzer shouldBeEmpty() { - if (!stdout.isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stdout was not empty"); + /** + * Verify that the stderr contents of output buffer is empty, + * after filtering out the Hotspot warning messages + * + * @throws RuntimeException + * If stderr was not empty + */ + public void stderrShouldBeEmptyIgnoreVMWarnings() { + if (!getStderr().replaceAll(jvmwarningmsg + "\\R", "").isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } } - if (!stderr.isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stderr was not empty"); + + /** + * Verify that the stdout contents of output buffer is not empty + * + * @throws RuntimeException + * If stdout was empty + */ + public void stdoutShouldNotBeEmpty() { + if (getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was empty"); + } } - return this; - } - /** - * Verify that the stdout contents of output buffer does not contain the string - * - * @param expectedString String that the buffer should not contain - * @throws RuntimeException If the string was found - */ - public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { - if (stdout.contains(notExpectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + /** + * Verify that the stderr contents of output buffer is not empty + * + * @throws RuntimeException + * If stderr was empty + */ + public void stderrShouldNotBeEmpty() { + if (getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was empty"); + } } - return this; - } - /** - * Verify that the stderr contents of output buffer does not contain the string - * - * @param expectedString String that the buffer should not contain - * @throws RuntimeException If the string was found - */ - public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { - if (stderr.contains(notExpectedString)) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + /** + * Verify that the stdout and stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer shouldContain(String expectedString) { + if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n"); + } + return this; } - return this; - } - /** - * Verify that the stdout and stderr contents of output buffer matches - * the pattern - * - * @param pattern - * @throws RuntimeException If the pattern was not found - */ - public OutputAnalyzer shouldMatch(String pattern) { - Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); - Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); - if (!stdoutMatcher.find() && !stderrMatcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' missing from stdout/stderr \n"); - } - return this; - } - - /** - * Verify that the stdout contents of output buffer matches the - * pattern - * - * @param pattern - * @throws RuntimeException If the pattern was not found - */ - public OutputAnalyzer stdoutShouldMatch(String pattern) { - Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); - if (!matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' missing from stdout \n"); - } - return this; - } - - /** - * Verify that the stderr contents of output buffer matches the - * pattern - * - * @param pattern - * @throws RuntimeException If the pattern was not found - */ - public OutputAnalyzer stderrShouldMatch(String pattern) { - - Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); - if (!matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' missing from stderr \n"); - } - return this; - } - - /** - * Verify that the stdout and stderr contents of output buffer does not - * match the pattern - * - * @param pattern - * @throws RuntimeException If the pattern was found - */ - public OutputAnalyzer shouldNotMatch(String pattern) { - Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); - if (matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' found in stdout: '" + matcher.group() + "' \n"); - } - matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); - if (matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' found in stderr: '" + matcher.group() + "' \n"); - } - return this; - } - - /** - * Verify that the stdout contents of output buffer does not match the - * pattern - * - * @param pattern - * @throws RuntimeException If the pattern was found - */ - public OutputAnalyzer stdoutShouldNotMatch(String pattern) { - Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); - if (matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' found in stdout \n"); - } - return this; - } - - /** - * Verify that the stderr contents of output buffer does not match the - * pattern - * - * @param pattern - * @throws RuntimeException If the pattern was found - */ - public OutputAnalyzer stderrShouldNotMatch(String pattern) { - Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); - if (matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' found in stderr \n"); - } - return this; - } - - /** - * Get the captured group of the first string matching the pattern. - * stderr is searched before stdout. - * - * @param pattern The multi-line pattern to match - * @param group The group to capture - * @return The matched string or null if no match was found - */ - public String firstMatch(String pattern, int group) { - Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); - Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); - if (stderrMatcher.find()) { - return stderrMatcher.group(group); + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer stdoutShouldContain(String expectedString) { + if (!stdout.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stdout \n"); + } + return this; } - if (stdoutMatcher.find()) { - return stdoutMatcher.group(group); + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer stderrShouldContain(String expectedString) { + if (!stderr.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stderr \n"); + } + return this; } - return null; - } - /** - * Get the first string matching the pattern. - * stderr is searched before stdout. - * - * @param pattern The multi-line pattern to match - * @return The matched string or null if no match was found - */ - public String firstMatch(String pattern) { - return firstMatch(pattern, 0); - } - - /** - * Verify the exit value of the process - * - * @param expectedExitValue Expected exit value from process - * @throws RuntimeException If the exit value from the process did not match the expected value - */ - public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { - if (getExitValue() != expectedExitValue) { - reportDiagnosticSummary(); - throw new RuntimeException("Expected to get exit value of [" - + expectedExitValue + "]\n"); - } - return this; - } - - /** - * Verify the exit value of the process - * - * @param notExpectedExitValue Unexpected exit value from process - * @throws RuntimeException If the exit value from the process did match the expected value - */ - public OutputAnalyzer shouldNotHaveExitValue(int notExpectedExitValue) { - if (getExitValue() == notExpectedExitValue) { - reportDiagnosticSummary(); - throw new RuntimeException("Unexpected to get exit value of [" - + notExpectedExitValue + "]\n"); - } - return this; - } - - - /** - * Report summary that will help to diagnose the problem - * Currently includes: - * - standard input produced by the process under test - * - standard output - * - exit code - * Note: the command line is printed by the ProcessTools - */ - public void reportDiagnosticSummary() { - String msg = - " stdout: [" + stdout + "];\n" + - " stderr: [" + stderr + "]\n" + - " exitValue = " + getExitValue() + "\n"; - - System.err.println(msg); - } - - /** - * Print the stdout buffer to the given {@code PrintStream}. - * - * @return this OutputAnalyzer - */ - public OutputAnalyzer outputTo(PrintStream out) { - out.println(getStdout()); - return this; - } - - /** - * Print the stderr buffer to the given {@code PrintStream}. - * - * @return this OutputAnalyzer - */ - public OutputAnalyzer errorTo(PrintStream out) { - out.println(getStderr()); - return this; - } - - /** - * Get the contents of the output buffer (stdout and stderr) - * - * @return Content of the output buffer - */ - public String getOutput() { - return stdout + stderr; - } - - /** - * Get the contents of the stdout buffer - * - * @return Content of the stdout buffer - */ - public String getStdout() { - return stdout; - } - - /** - * Get the contents of the stderr buffer - * - * @return Content of the stderr buffer - */ - public String getStderr() { - return stderr; - } - - /** - * Get the process exit value - * - * @return Process exit value - */ - public int getExitValue() { - return exitValue; - } - - /** - * Get the contents of the output buffer (stdout and stderr) as list of strings. - * Output will be split by newlines. - * - * @return Contents of the output buffer as list of strings - */ - public List asLines() { - return asLines(getOutput()); - } - - private List asLines(String buffer) { - return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)")); - } - - - private static final String jvmwarningmsg = ".* VM warning:.*"; - - /** - * Verifies that the stdout and stderr contents of output buffer are empty, after - * filtering out the HotSpot warning messages. - * - * @throws RuntimeException If the stdout and stderr are not empty - */ - public OutputAnalyzer shouldBeEmptyIgnoreVMWarnings() { - if (!stdout.isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stdout was not empty"); + /** + * Verify that the stdout and stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer shouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + } + if (stderr.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + } + return this; } - if (!stderr.replaceAll(jvmwarningmsg + "\\R", "").isEmpty()) { - reportDiagnosticSummary(); - throw new RuntimeException("stderr was not empty"); + + /** + * Verify that the stdout and stderr contents of output buffer are empty + * + * @throws RuntimeException If the stdout and stderr are not empty + */ + public OutputAnalyzer shouldBeEmpty() { + if (!stdout.isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was not empty"); + } + if (!stderr.isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } + return this; } - return this; - } - /** - * Verify that the stderr contents of output buffer matches the pattern, - * after filtering out the Hotespot warning messages - * - * @param pattern - * @throws RuntimeException If the pattern was not found - */ - public OutputAnalyzer stderrShouldMatchIgnoreVMWarnings(String pattern) { - String stderr = this.stderr.replaceAll(jvmwarningmsg + "\\R", ""); - Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); - if (!matcher.find()) { - reportDiagnosticSummary(); - throw new RuntimeException("'" + pattern - + "' missing from stderr \n"); - } - return this; - } + /** + * Verify that the stdout contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + } + return this; + } - /** - * Returns the contents of the output buffer (stdout and stderr), without those - * JVM warning msgs, as list of strings. Output is split by newlines. - * - * @return Contents of the output buffer as list of strings - */ - public List asLinesWithoutVMWarnings() { - return Arrays.asList(getOutput().split("\\R")) - .stream() - .filter(Pattern.compile(jvmwarningmsg).asPredicate().negate()) - .collect(Collectors.toList()); - } + /** + * Verify that the stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { + if (stderr.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer matches + * the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer shouldMatch(String pattern) { + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!stdoutMatcher.find() && !stderrMatcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stdoutShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stderrShouldMatch(String pattern) { + + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * match the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer shouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stdout: '" + matcher.group() + "' \n"); + } + matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stderr: '" + matcher.group() + "' \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer stdoutShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer stderrShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stderr \n"); + } + return this; + } + + /** + * Get the captured group of the first string matching the pattern. + * stderr is searched before stdout. + * + * @param pattern The multi-line pattern to match + * @param group The group to capture + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern, int group) { + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (stderrMatcher.find()) { + return stderrMatcher.group(group); + } + if (stdoutMatcher.find()) { + return stdoutMatcher.group(group); + } + return null; + } + + /** + * Get the first string matching the pattern. + * stderr is searched before stdout. + * + * @param pattern The multi-line pattern to match + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern) { + return firstMatch(pattern, 0); + } + + /** + * Verify the exit value of the process + * + * @param expectedExitValue Expected exit value from process + * @throws RuntimeException If the exit value from the process did not match the expected value + */ + public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { + if (getExitValue() != expectedExitValue) { + reportDiagnosticSummary(); + throw new RuntimeException("Expected to get exit value of [" + + expectedExitValue + "]\n"); + } + return this; + } + + /** + * Verify the exit value of the process + * + * @param notExpectedExitValue Unexpected exit value from process + * @throws RuntimeException If the exit value from the process did match the expected value + */ + public OutputAnalyzer shouldNotHaveExitValue(int notExpectedExitValue) { + if (getExitValue() == notExpectedExitValue) { + reportDiagnosticSummary(); + throw new RuntimeException("Unexpected to get exit value of [" + + notExpectedExitValue + "]\n"); + } + return this; + } + + + /** + * Report summary that will help to diagnose the problem + * Currently includes: + * - standard input produced by the process under test + * - standard output + * - exit code + * Note: the command line is printed by the ProcessTools + */ + public void reportDiagnosticSummary() { + String msg = + " stdout: [" + stdout + "];\n" + + " stderr: [" + stderr + "]\n" + + " exitValue = " + getExitValue() + "\n"; + + System.err.println(msg); + } + + /** + * Print the stdout buffer to the given {@code PrintStream}. + * + * @return this OutputAnalyzer + */ + public OutputAnalyzer outputTo(PrintStream out) { + out.println(getStdout()); + return this; + } + + /** + * Print the stderr buffer to the given {@code PrintStream}. + * + * @return this OutputAnalyzer + */ + public OutputAnalyzer errorTo(PrintStream out) { + out.println(getStderr()); + return this; + } + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return stdout + stderr; + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return stdout; + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return stderr; + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return exitValue; + } + + /** + * Get the contents of the output buffer (stdout and stderr) as list of strings. + * Output will be split by newlines. + * + * @return Contents of the output buffer as list of strings + */ + public List asLines() { + return asLines(getOutput()); + } + + private List asLines(String buffer) { + return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)")); + } + + + private static final String jvmwarningmsg = ".* VM warning:.*"; + + /** + * Verifies that the stdout and stderr contents of output buffer are empty, after + * filtering out the HotSpot warning messages. + * + * @throws RuntimeException If the stdout and stderr are not empty + */ + public OutputAnalyzer shouldBeEmptyIgnoreVMWarnings() { + if (!stdout.isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was not empty"); + } + if (!stderr.replaceAll(jvmwarningmsg + "\\R", "").isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer matches the pattern, + * after filtering out the Hotespot warning messages + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stderrShouldMatchIgnoreVMWarnings(String pattern) { + String stderr = this.stderr.replaceAll(jvmwarningmsg + "\\R", ""); + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stderr \n"); + } + return this; + } + + /** + * Returns the contents of the output buffer (stdout and stderr), without those + * JVM warning msgs, as list of strings. Output is split by newlines. + * + * @return Contents of the output buffer as list of strings + */ + public List asLinesWithoutVMWarnings() { + return Arrays.asList(getOutput().split("\\R")) + .stream() + .filter(Pattern.compile(jvmwarningmsg).asPredicate().negate()) + .collect(Collectors.toList()); + } } From 7904b563454b72855e7bd8616b94db1f8d7c6449 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gopularam Date: Wed, 25 Apr 2018 12:44:50 +0530 Subject: [PATCH 039/102] 8200101: sun/security/krb5/auto/Renewal.java fails intermittently Reviewed-by: weijun --- test/jdk/sun/security/krb5/auto/Renewal.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/krb5/auto/Renewal.java b/test/jdk/sun/security/krb5/auto/Renewal.java index 907fc77acae..1d0417f89e5 100644 --- a/test/jdk/sun/security/krb5/auto/Renewal.java +++ b/test/jdk/sun/security/krb5/auto/Renewal.java @@ -161,8 +161,10 @@ public class Renewal { return; } long change = (t.getTime() - System.currentTimeMillis()) / 1000; - if (change > duration + 20 || change < duration - 20) { - throw new Exception(t + " is not " + duration); + //accounting the delay factor in processing the instructions on host mc + if (change > duration + 40 || change < duration - 40) { + throw new Exception("Timestamp is " + t + ", actual difference " + + change + " is not " + duration); } } } From eed00fcf0a0cc1a1a4499e0aa688d2cc537b5735 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 25 Apr 2018 13:54:11 +0200 Subject: [PATCH 040/102] 8202184: Reduce time blocking the ClassSpecializer cache creating SpeciesData Reviewed-by: psandoz, plevart --- .../java/lang/invoke/ClassSpecializer.java | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java index 5756a775dee..c20d691e6aa 100644 --- a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java +++ b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java @@ -32,13 +32,17 @@ import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.BytecodeName; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.ProtectionDomain; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.function.Function; import static java.lang.invoke.LambdaForm.*; @@ -64,7 +68,7 @@ abstract class ClassSpecializer.SpeciesDat private final List transformMethods; private final MethodType baseConstructorType; private final S topSpecies; - private final ConcurrentMap cache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap cache = new ConcurrentHashMap<>(); private final Factory factory; private @Stable boolean topClassIsSuper; @@ -113,8 +117,7 @@ abstract class ClassSpecializer.SpeciesDat this.keyType = keyType; this.metaType = metaType; this.sdAccessor = sdAccessor; - // FIXME: use List.copyOf once 8177290 is in - this.transformMethods = List.of(transformMethods.toArray(new MemberName[transformMethods.size()])); + this.transformMethods = List.copyOf(transformMethods); this.sdFieldName = sdFieldName; this.baseConstructorType = baseConstructorType.changeReturnType(void.class); this.factory = makeFactory(); @@ -149,12 +152,6 @@ abstract class ClassSpecializer.SpeciesDat } public final S findSpecies(K key) { - S speciesData = cache.computeIfAbsent(key, new Function<>() { - @Override - public S apply(K key1) { - return factory.loadSpecies(newSpeciesData(key1)); - } - }); // Note: Species instantiation may throw VirtualMachineError because of // code cache overflow. If this happens the species bytecode may be // loaded but not linked to its species metadata (with MH's etc). @@ -176,7 +173,33 @@ abstract class ClassSpecializer.SpeciesDat // successfully on a concrete class if ever. // The concrete class is published via SpeciesData instance // returned here only after the class and species data are linked together. - assert(speciesData != null); + S speciesData = cache.computeIfAbsent(key, new Function<>() { + @Override + public S apply(K key1) { + return newSpeciesData(key1); + } + }); + // Separating the creation of a placeholder SpeciesData instance above + // from the loading and linking a real one below ensures we can never + // accidentally call computeIfAbsent recursively. Replacing rather than + // updating the placeholder is done to ensure safe publication. + if (!speciesData.isResolved()) { + synchronized (speciesData) { + S existingSpeciesData = cache.get(key); + if (existingSpeciesData == speciesData) { // won the race + // create a new SpeciesData... + speciesData = newSpeciesData(key); + // load and link it... + speciesData = factory.loadSpecies(speciesData); + if (!cache.replace(key, existingSpeciesData, speciesData)) { + throw newInternalError("Concurrent loadSpecies"); + } + } else { // lost the race; the retrieved existingSpeciesData is the final + speciesData = existingSpeciesData; + } + } + } + assert(speciesData != null && speciesData.isResolved()); return speciesData; } @@ -208,9 +231,7 @@ abstract class ClassSpecializer.SpeciesDat protected SpeciesData(K key) { this.key = keyType.cast(Objects.requireNonNull(key)); List> types = deriveFieldTypes(key); - // TODO: List.copyOf - int arity = types.size(); - this.fieldTypes = List.of(types.toArray(new Class[arity])); + this.fieldTypes = List.copyOf(types); } public final K key() { @@ -458,8 +479,8 @@ abstract class ClassSpecializer.SpeciesDat final Class speciesCode; if (salvage != null) { speciesCode = salvage.asSubclass(topClass()); - factory.linkSpeciesDataToCode(speciesData, speciesCode); - factory.linkCodeToSpeciesData(speciesCode, speciesData, true); + linkSpeciesDataToCode(speciesData, speciesCode); + linkCodeToSpeciesData(speciesCode, speciesData, true); } else { // Not pregenerated, generate the class try { @@ -486,7 +507,7 @@ abstract class ClassSpecializer.SpeciesDat if (!speciesData.isResolved()) { throw newInternalError("bad species class linkage for " + className + ": " + speciesData); } - assert(speciesData == factory.loadSpeciesDataFromCode(speciesCode)); + assert(speciesData == loadSpeciesDataFromCode(speciesCode)); return speciesData; } From d571253203d85465072debe6a489fe92e4ea4c76 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 25 Apr 2018 14:53:35 +0200 Subject: [PATCH 041/102] 8202210: jlink uses little-endian for big-endian cross-compilation targets Reviewed-by: ihse, alanb, stuefe --- make/Images.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/Images.gmk b/make/Images.gmk index 2e5ddba2147..3514d2f3ee6 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -117,7 +117,7 @@ JLINK_ORDER_RESOURCES += \ JLINK_TOOL := $(JLINK) -J-Djlink.debug=true \ --module-path $(IMAGES_OUTPUTDIR)/jmods \ - --endian $(OPENJDK_BUILD_CPU_ENDIAN) \ + --endian $(OPENJDK_TARGET_CPU_ENDIAN) \ --release-info $(BASE_RELEASE_FILE) \ --order-resources=$(call CommaList, $(JLINK_ORDER_RESOURCES)) \ --dedup-legal-notices=error-if-not-same-content \ From fa434f6934c16d7b6697f01b651440c9eeb343ac Mon Sep 17 00:00:00 2001 From: Bernard Blaser Date: Wed, 25 Apr 2018 09:45:45 -0700 Subject: [PATCH 042/102] 8202141: Unique symbols for .class Reviewed-by: vromero, jlahoda --- .../com/sun/tools/javac/code/Symtab.java | 23 +++- .../com/sun/tools/javac/comp/Attr.java | 12 +- .../ClassFieldDeduplication.java | 117 ++++++++++++++++++ .../lambda/deduplication/Deduplication.java | 25 ++++ 4 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 test/langtools/tools/javac/lambda/deduplication/ClassFieldDeduplication.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 64aa1c73027..4828b7d47a9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,7 @@ import com.sun.tools.javac.code.Type.JCPrimitiveType; import com.sun.tools.javac.code.Type.JCVoidType; import com.sun.tools.javac.code.Type.MethodType; import com.sun.tools.javac.code.Type.UnknownType; +import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Modules; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; @@ -247,6 +248,26 @@ public class Symtab { */ private final Map modules = new LinkedHashMap<>(); + private final Map classFields = new HashMap<>(); + + public VarSymbol getClassField(Type type, Types types) { + return classFields.computeIfAbsent( + new UniqueType(type, types), k -> { + Type arg = null; + if (type.getTag() == ARRAY || type.getTag() == CLASS) + arg = types.erasure(type); + else if (type.isPrimitiveOrVoid()) + arg = types.boxedClass(type).type; + else + throw new AssertionError(type); + + Type t = new ClassType( + classType.getEnclosingType(), List.of(arg), classType.tsym); + return new VarSymbol( + STATIC | PUBLIC | FINAL, names._class, t, type.tsym); + }); + } + public void initType(Type type, ClassSymbol c) { type.tsym = c; typeOfTag[type.getTag().ordinal()] = type; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index e647a6d8add..8871e66a596 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -3731,11 +3731,7 @@ public class Attr extends JCTree.Visitor { } else if (name == names._class) { // In this case, we have already made sure in // visitSelect that qualifier expression is a type. - Type t = syms.classType; - List typeargs = List.of(types.erasure(site)); - t = new ClassType(t.getEnclosingType(), typeargs, t.tsym); - return new VarSymbol( - STATIC | PUBLIC | FINAL, names._class, t, site.tsym); + return syms.getClassField(site, types); } else { // We are seeing a plain identifier as selector. Symbol sym = rs.findIdentInType(env, site, name, resultInfo.pkind); @@ -3773,11 +3769,7 @@ public class Attr extends JCTree.Visitor { if (name == names._class) { // In this case, we have already made sure in Select that // qualifier expression is a type. - Type t = syms.classType; - Type arg = types.boxedClass(site).type; - t = new ClassType(t.getEnclosingType(), List.of(arg), t.tsym); - return new VarSymbol( - STATIC | PUBLIC | FINAL, names._class, t, site.tsym); + return syms.getClassField(site, types); } else { log.error(pos, Errors.CantDeref(site)); return syms.errSymbol; diff --git a/test/langtools/tools/javac/lambda/deduplication/ClassFieldDeduplication.java b/test/langtools/tools/javac/lambda/deduplication/ClassFieldDeduplication.java new file mode 100644 index 00000000000..35f875af29d --- /dev/null +++ b/test/langtools/tools/javac/lambda/deduplication/ClassFieldDeduplication.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8202141 + * @summary Verify that .class synthetic Symbols are not duplicated. + * @library /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main ClassFieldDeduplication + */ + +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.TreeScanner; +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTestHelper; + +public class ClassFieldDeduplication extends ComboInstance { + + enum Type implements ComboParameter { + OBJECT("Object"), + PRIMITIVE("int"), + BOXED_PRIMITIVE("Integer"), + VOID("void"), + BOXED_VOID("Void"), + OBJECT_ARRAY("Object[]"), + PRIMITIVE_ARRAY("int[]"), + BOXED_PRIMITIVE_ARRAY("Integer[]"), + BOXED_VOID_ARRAY("Void[]"); + + String type; + + Type(String type) { + this.type = type; + } + + @Override + public String expand(String optParameter) { + return type; + } + + } + + public static void main(String... args) throws Exception { + new ComboTestHelper() + .withDimension("TYPE", Type.values()) + .run(ClassFieldDeduplication::new); + } + + private static final String TEMPLATE = + "class Test { void t() { Object o1 = #{TYPE}.class; Object o2 = #{TYPE}.class; } }"; + + @Override + protected void doWork() throws Throwable { + newCompilationTask() + .withSourceFromTemplate(TEMPLATE) + .withListener(new TaskListener() { + JCCompilationUnit cut; + @Override + public void finished(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.PARSE) { + if (cut != null) + throw new AssertionError(); + cut = (JCCompilationUnit) e.getCompilationUnit(); + } + if (e.getKind() == TaskEvent.Kind.ANALYZE) { + cut.accept(new TreeScanner() { + Symbol s; + @Override + public void visitSelect(JCFieldAccess tree) { + if (tree.name.contentEquals("class")) { + if (s == null) { + s = tree.sym; + } else if (s != tree.sym) { + throw new AssertionError("Duplicated field symbol."); + } + } + super.visitSelect(tree); + } + }); + } + } + + }) + .analyze(els -> {}); + } + +} diff --git a/test/langtools/tools/javac/lambda/deduplication/Deduplication.java b/test/langtools/tools/javac/lambda/deduplication/Deduplication.java index 74e6e0fa285..46f891a3e71 100644 --- a/test/langtools/tools/javac/lambda/deduplication/Deduplication.java +++ b/test/langtools/tools/javac/lambda/deduplication/Deduplication.java @@ -38,6 +38,31 @@ public class Deduplication { (Runnable) () -> { ( (Runnable) () -> {} ).run(); } ); + group( + (Runnable) () -> { Deduplication.class.toString(); }, + (Runnable) () -> { Deduplication.class.toString(); } + ); + + group( + (Runnable) () -> { Integer[].class.toString(); }, + (Runnable) () -> { Integer[].class.toString(); } + ); + + group( + (Runnable) () -> { char.class.toString(); }, + (Runnable) () -> { char.class.toString(); } + ); + + group( + (Runnable) () -> { Void.class.toString(); }, + (Runnable) () -> { Void.class.toString(); } + ); + + group( + (Runnable) () -> { void.class.toString(); }, + (Runnable) () -> { void.class.toString(); } + ); + group((Function) x -> x.hashCode()); group((Function) x -> x.hashCode()); From 5096bee84e6aea1c78e0f21b1d426713dcde72a0 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 25 Apr 2018 10:12:45 -0700 Subject: [PATCH 043/102] 8202152: test/hotspot/jtreg/runtime/whitebox/WBStackSize.java fails Set compiler threads stack size the same as for java threads Reviewed-by: dholmes, mdoerr, dlong --- test/hotspot/jtreg/runtime/whitebox/WBStackSize.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java b/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java index f702864e5a7..3720b7a5680 100644 --- a/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java +++ b/test/hotspot/jtreg/runtime/whitebox/WBStackSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,8 @@ * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xss512k WBStackSize + * @comment Must use the same stacksize for Java threads and compiler threads in case of thread recycling + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xss512k -XX:CompilerThreadStackSize=512 WBStackSize */ /* @@ -82,9 +83,7 @@ public class WBStackSize { } public static void main(String[] args) { - boolean isCompilerThread = Thread.currentThread().getName().indexOf(" CompilerThread") > 0; - long configStackSize = isCompilerThread ? wb.getIntxVMFlag("CompilerThreadStackSize") * K - : wb.getIntxVMFlag("ThreadStackSize") * K; + long configStackSize = wb.getIntxVMFlag("ThreadStackSize") * K; System.out.println("ThreadStackSize VM option: " + configStackSize); long stackProtectionSize = wb.getIntxVMFlag("StackShadowPages") * wb.getVMPageSize(); @@ -95,7 +94,7 @@ public class WBStackSize { if (Math.abs(actualStackSize - configStackSize) > configStackSize * 0.1) { throw new RuntimeException("getThreadFullStackSize value [" + actualStackSize - + "] should be within 90%..110% of the value returned by HotSpotDiagnosticMXBean"); + + "] should be within 90%..110% of ThreadStackSize value"); } long remainingStackSize = wb.getThreadRemainingStackSize(); From 465eea6d80b0dd9d875e7a164b09797e02b52f7d Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Wed, 25 Apr 2018 11:24:33 -0700 Subject: [PATCH 044/102] 8202276: Update test/hotspot/jtreg/ProblemList-graal.txt Reviewed-by: kvn --- test/hotspot/jtreg/ProblemList-graal.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-graal.txt b/test/hotspot/jtreg/ProblemList-graal.txt index 4de9eb0503d..6b4700d91f2 100644 --- a/test/hotspot/jtreg/ProblemList-graal.txt +++ b/test/hotspot/jtreg/ProblemList-graal.txt @@ -73,3 +73,14 @@ serviceability/jvmti/GetModulesInfo/JvmtiGetAllModulesTest.java 8195156 generi compiler/compilercontrol/directives/LogTest.java 8181753 generic-all gc/g1/ihop/TestIHOPStatic.java 8199486 generic-all + +compiler/jvmci/compilerToVM/ReprofileTest.java 8201333 generic-all + +compiler/tiered/TieredLevelsTest.java 8202124 generic-all +compiler/tiered/NonTieredLevelsTest.java 8202124 generic-all +compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java 8202124 generic-all + +compiler/jvmci/meta/StableFieldTest.java CODETOOLS-7902162 generic-all +compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotConstantReflectionProviderTest.java CODETOOLS-7902162 generic-all +compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderTest.java CODETOOLS-7902162 generic-all +compiler/jvmci/events/JvmciShutdownEventTest.java CODETOOLS-7902162 generic-all From 8a427a07d8d3ddc2ec9016313ebbcc7f455d76bd Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 25 Apr 2018 17:50:32 -0400 Subject: [PATCH 045/102] 8202164: Remove some unneeded BoolObjectClosure* is_alive parameters Reviewed-by: kbarrett, stefank --- src/hotspot/share/aot/aotCompiledMethod.hpp | 2 +- src/hotspot/share/code/compiledMethod.cpp | 28 ++++++++-------- src/hotspot/share/code/compiledMethod.hpp | 4 +-- src/hotspot/share/code/nmethod.cpp | 36 ++++++++++----------- src/hotspot/share/code/nmethod.hpp | 6 ++-- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- 6 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/hotspot/share/aot/aotCompiledMethod.hpp b/src/hotspot/share/aot/aotCompiledMethod.hpp index d6fecabb36e..9e9a19f0c15 100644 --- a/src/hotspot/share/aot/aotCompiledMethod.hpp +++ b/src/hotspot/share/aot/aotCompiledMethod.hpp @@ -285,7 +285,7 @@ private: protected: virtual bool do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred); - virtual bool do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred) { return false; } + virtual bool do_unloading_jvmci(bool unloading_occurred) { return false; } }; diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp index 7250d6af124..a4332f56d09 100644 --- a/src/hotspot/share/code/compiledMethod.cpp +++ b/src/hotspot/share/code/compiledMethod.cpp @@ -525,7 +525,7 @@ void CompiledMethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_oc } #if INCLUDE_JVMCI - if (do_unloading_jvmci(is_alive, unloading_occurred)) { + if (do_unloading_jvmci(unloading_occurred)) { return; } #endif @@ -535,7 +535,7 @@ void CompiledMethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_oc } template -static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, BoolObjectClosure *is_alive, CompiledMethod* from) { +static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, CompiledMethod* from) { // Ok, to lookup references to zombies here CodeBlob *cb = CodeCache::find_blob_unsafe(addr); CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL; @@ -555,12 +555,12 @@ static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address add return false; } -static bool clean_if_nmethod_is_unloaded(CompiledIC *ic, BoolObjectClosure *is_alive, CompiledMethod* from) { - return clean_if_nmethod_is_unloaded(ic, ic->ic_destination(), is_alive, from); +static bool clean_if_nmethod_is_unloaded(CompiledIC *ic, CompiledMethod* from) { + return clean_if_nmethod_is_unloaded(ic, ic->ic_destination(), from); } -static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, BoolObjectClosure *is_alive, CompiledMethod* from) { - return clean_if_nmethod_is_unloaded(csc, csc->destination(), is_alive, from); +static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, CompiledMethod* from) { + return clean_if_nmethod_is_unloaded(csc, csc->destination(), from); } bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred) { @@ -608,15 +608,15 @@ bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unl clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); } - postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); + postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this); break; case relocInfo::opt_virtual_call_type: - postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); + postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this); break; case relocInfo::static_call_type: - postponed |= clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), is_alive, this); + postponed |= clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), this); break; case relocInfo::oop_type: @@ -636,7 +636,7 @@ bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unl } #if INCLUDE_JVMCI - if (do_unloading_jvmci(is_alive, unloading_occurred)) { + if (do_unloading_jvmci(unloading_occurred)) { return postponed; } #endif @@ -647,7 +647,7 @@ bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unl return postponed; } -void CompiledMethod::do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred) { +void CompiledMethod::do_unloading_parallel_postponed() { ResourceMark rm; // Make sure the oop's ready to receive visitors @@ -671,15 +671,15 @@ void CompiledMethod::do_unloading_parallel_postponed(BoolObjectClosure* is_alive switch (iter.type()) { case relocInfo::virtual_call_type: - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); + clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this); break; case relocInfo::opt_virtual_call_type: - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); + clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this); break; case relocInfo::static_call_type: - clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), is_alive, this); + clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), this); break; default: diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp index 87bde4bea81..d281405ee0c 100644 --- a/src/hotspot/share/code/compiledMethod.hpp +++ b/src/hotspot/share/code/compiledMethod.hpp @@ -372,7 +372,7 @@ public: virtual void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred); // The parallel versions are used by G1. virtual bool do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_occurred); - virtual void do_unloading_parallel_postponed(BoolObjectClosure* is_alive, bool unloading_occurred); + virtual void do_unloading_parallel_postponed(); static unsigned char global_unloading_clock() { return _global_unloading_clock; } static void increase_unloading_clock(); @@ -383,7 +383,7 @@ public: protected: virtual bool do_unloading_oops(address low_boundary, BoolObjectClosure* is_alive, bool unloading_occurred) = 0; #if INCLUDE_JVMCI - virtual bool do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred) = 0; + virtual bool do_unloading_jvmci(bool unloading_occurred) = 0; #endif private: diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c6e4f9e0ad5..2524af406c9 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1028,17 +1028,16 @@ void nmethod::inc_decompile_count() { mdo->inc_decompile_count(); } -void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { +void nmethod::make_unloaded(oop cause) { post_compiled_method_unload(); - // Since this nmethod is being unloaded, make sure that dependencies - // recorded in instanceKlasses get flushed and pass non-NULL closure to - // indicate that this work is being done during a GC. + // This nmethod is being unloaded, make sure that dependencies + // recorded in instanceKlasses get flushed. + // Since this work is being done during a GC, defer deleting dependencies from the + // InstanceKlass. assert(Universe::heap()->is_gc_active(), "should only be called during gc"); - assert(is_alive != NULL, "Should be non-NULL"); - // A non-NULL is_alive closure indicates that this is being called during GC. - flush_dependencies(is_alive); + flush_dependencies(/*delete_immediately*/false); // Break cycle between nmethod & method LogTarget(Trace, class, unload) lt; @@ -1261,7 +1260,7 @@ bool nmethod::make_not_entrant_or_zombie(int state) { if (nmethod_needs_unregister) { Universe::heap()->unregister_nmethod(this); } - flush_dependencies(NULL); + flush_dependencies(/*delete_immediately*/true); } // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload @@ -1344,13 +1343,13 @@ void nmethod::flush() { // of dependencies must happen during phase 1 since after GC any // dependencies in the unloaded nmethod won't be updated, so // traversing the dependency information in unsafe. In that case this -// function is called with a non-NULL argument and this function only +// function is called with a boolean argument and this function only // notifies instanceKlasses that are reachable -void nmethod::flush_dependencies(BoolObjectClosure* is_alive) { +void nmethod::flush_dependencies(bool delete_immediately) { assert_locked_or_safepoint(CodeCache_lock); - assert(Universe::heap()->is_gc_active() == (is_alive != NULL), - "is_alive is non-NULL if and only if we are called during GC"); + assert(Universe::heap()->is_gc_active() != delete_immediately, + "delete_immediately is false if and only if we are called during GC"); if (!has_flushed_dependencies()) { set_has_flushed_dependencies(); for (Dependencies::DepStream deps(this); deps.next(); ) { @@ -1363,13 +1362,12 @@ void nmethod::flush_dependencies(BoolObjectClosure* is_alive) { if (klass == NULL) { continue; // ignore things like evol_method } - // During GC the is_alive closure is non-NULL, and is used to - // determine liveness of dependees that need to be updated. - if (is_alive == NULL || klass->is_loader_alive()) { + // During GC delete_immediately is false, and liveness + // of dependee determines class that needs to be updated. + if (delete_immediately || klass->is_loader_alive()) { // The GC defers deletion of this entry, since there might be multiple threads // iterating over the _dependencies graph. Other call paths are single-threaded // and may delete it immediately. - bool delete_immediately = is_alive == NULL; InstanceKlass::cast(klass)->remove_dependent_nmethod(this, delete_immediately); } } @@ -1390,7 +1388,7 @@ bool nmethod::can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_ // simply because one of its constant oops has gone dead. // No actual classes need to be unloaded in order for this to occur. assert(unloading_occurred || ScavengeRootsInCode, "Inconsistency in unloading"); - make_unloaded(is_alive, obj); + make_unloaded(obj); return true; } @@ -1516,12 +1514,12 @@ bool nmethod::do_unloading_oops(address low_boundary, BoolObjectClosure* is_aliv } #if INCLUDE_JVMCI -bool nmethod::do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred) { +bool nmethod::do_unloading_jvmci(bool unloading_occurred) { if (_jvmci_installed_code != NULL) { if (JNIHandles::is_global_weak_cleared(_jvmci_installed_code)) { if (_jvmci_installed_code_triggers_unloading) { // jweak reference processing has already cleared the referent - make_unloaded(is_alive, NULL); + make_unloaded(NULL); return true; } else { clear_jvmci_installed_code(); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 8cbf73ed098..ed37c129ce2 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -349,10 +349,10 @@ class nmethod : public CompiledMethod { return _state; } - void make_unloaded(BoolObjectClosure* is_alive, oop cause); + void make_unloaded(oop cause); bool has_dependencies() { return dependencies_size() != 0; } - void flush_dependencies(BoolObjectClosure* is_alive); + void flush_dependencies(bool delete_immediately); bool has_flushed_dependencies() { return _has_flushed_dependencies; } void set_has_flushed_dependencies() { assert(!has_flushed_dependencies(), "should only happen once"); @@ -488,7 +488,7 @@ public: #if INCLUDE_JVMCI // See comment for _jvmci_installed_code_triggers_unloading field. // Returns whether this nmethod was unloaded. - virtual bool do_unloading_jvmci(BoolObjectClosure* is_alive, bool unloading_occurred); + virtual bool do_unloading_jvmci(bool unloading_occurred); #endif private: diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 33cee250b01..246714c512b 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3353,7 +3353,7 @@ private: } void clean_nmethod_postponed(CompiledMethod* nm) { - nm->do_unloading_parallel_postponed(_is_alive, _unloading_occurred); + nm->do_unloading_parallel_postponed(); } static const int MaxClaimNmethods = 16; From c3efc6ec43b02359e7fff5c76550aead4529b2f9 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 26 Apr 2018 09:45:47 +0900 Subject: [PATCH 046/102] 8199519: Several GC tests fails with: java.lang.NumberFormatException: Unparseable number: "-" Reviewed-by: sjohanss, jgeorge --- .../classes/sun/tools/jstat/ColumnFormat.java | 17 +++++++++++++++-- .../classes/sun/tools/jstat/Expression.java | 19 ++++++++++++++++++- .../sun/tools/jstat/ExpressionResolver.java | 8 +++++--- .../share/classes/sun/tools/jstat/Parser.java | 19 +++++++++++++++++-- .../sun/tools/jstat/resources/jstat_options | 6 ++++++ test/hotspot/jtreg/ProblemList.txt | 5 ----- .../jstat/utils/JstatGcCauseResults.java | 14 +++++++++++--- .../tmtools/jstat/utils/JstatGcResults.java | 14 +++++++++++--- .../jdk/sun/tools/jstat/gcCapacityOutput1.awk | 2 +- .../sun/tools/jstat/gcMetaCapacityOutput1.awk | 2 +- .../sun/tools/jstat/gcNewCapacityOutput1.awk | 2 +- .../sun/tools/jstat/gcOldCapacityOutput1.awk | 2 +- test/jdk/sun/tools/jstat/gcOldOutput1.awk | 2 +- test/jdk/sun/tools/jstat/gcOutput1.awk | 2 +- 14 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java index 685b97886b8..fc0dfe0483c 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/ColumnFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ public class ColumnFormat extends OptionFormat { private String format; private String header; private Expression expression; + private boolean required = false; private Object previousValue; public ColumnFormat(int number) { @@ -71,6 +72,9 @@ public class ColumnFormat extends OptionFormat { // the raw data. format="0"; } + + // Adjust required flag + expression.setRequired(required); } public void setWidth(int width) { @@ -121,6 +125,14 @@ public class ColumnFormat extends OptionFormat { this.expression = e; } + public void setRequired(boolean r) { + this.required = r; + } + + public boolean isRequired() { + return this.required; + } + public void setPreviousValue(Object o) { this.previousValue = o; } @@ -141,7 +153,8 @@ public class ColumnFormat extends OptionFormat { System.out.println(indent + indentAmount + "name=" + name + ";data=" + expression.toString() + ";header=" + header + ";format=" + format + ";width=" + width - + ";scale=" + scale.toString() + ";align=" + align.toString()); + + ";scale=" + scale.toString() + ";align=" + align.toString() + + ";required=" + required); for (Iterator i = children.iterator(); i.hasNext(); /* empty */) { OptionFormat of = i.next(); diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/Expression.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/Expression.java index ea985738699..5f6e47177fe 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/Expression.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/Expression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ public class Expression { private Expression right; private Operator operator; private int ordinal = nextOrdinal++; + private boolean required = false; Expression() { if (debug) { @@ -52,6 +53,7 @@ public class Expression { System.out.println("Setting left on " + ordinal + " to " + left); } this.left = left; + this.left.setRequired(required); } Expression getLeft() { @@ -63,6 +65,7 @@ public class Expression { System.out.println("Setting right on " + ordinal + " to " + right); } this.right = right; + this.right.setRequired(required); } Expression getRight() { @@ -80,6 +83,20 @@ public class Expression { return operator; } + void setRequired(boolean r) { + this.required = r; + if (left != null) { + left.setRequired(required); + } + if (right != null) { + right.setRequired(required); + } + } + + boolean isRequired() { + return required; + } + public String toString() { StringBuilder b = new StringBuilder(); b.append('('); diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java index 58b02dc4a77..98602df2207 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/ExpressionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,7 +73,7 @@ public class ExpressionResolver implements ExpressionEvaluator { System.err.println("Warning: Unresolved Symbol: " + id.getName() + " substituted NaN"); } - return new Literal(Double.valueOf(Double.NaN)); + return new Literal(e.isRequired() ? 0.0d : Double.NaN); } if (m.getVariability() == Variability.CONSTANT) { if (debug) { @@ -131,7 +131,9 @@ public class ExpressionResolver implements ExpressionEvaluator { + " (right = " + rn.doubleValue() + ")" + " to literal value " + result); } - return new Literal(Double.valueOf(result)); + var literal = new Literal(result); + literal.setRequired(e.isRequired()); + return literal; } } diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java index a9f9b203e20..5693e422fe6 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,13 +60,15 @@ public class Parser { private static final String FORMAT = "format"; private static final String ALIGN = "align"; private static final String SCALE = "scale"; + private static final String REQUIRED = "required"; private static final String START = OPTION; private static final Set scaleKeyWords = Scale.keySet(); private static final Set alignKeyWords = Alignment.keySet(); + private static final Set boolKeyWords = Set.of("true", "false"); private static String[] otherKeyWords = { - OPTION, COLUMN, DATA, HEADER, WIDTH, FORMAT, ALIGN, SCALE + OPTION, COLUMN, DATA, HEADER, WIDTH, FORMAT, ALIGN, SCALE, REQUIRED }; private static char[] infixOps = { @@ -444,6 +446,16 @@ public class Parser { log(pdebug, "Parsed: data -> " + e); } + /** + * requiredstmt -> 'required' expression + */ + private void requiredStmt(ColumnFormat cf) throws ParserException, IOException { + match(REQUIRED); + Token t = matchOne(boolKeyWords); + cf.setRequired(Boolean.parseBoolean(t.sval)); + log(pdebug, "Parsed: required -> " + cf.isRequired()); + } + /** * statementlist -> optionalstmt statementlist * optionalstmt -> 'data' expression @@ -452,6 +464,7 @@ public class Parser { * 'format' formatstring * 'align' alignspec * 'scale' scalespec + * 'required' boolean */ private void statementList(ColumnFormat cf) throws ParserException, IOException { @@ -472,6 +485,8 @@ public class Parser { alignStmt(cf); } else if (lookahead.sval.compareTo(SCALE) == 0) { scaleStmt(cf); + } else if (lookahead.sval.compareTo(REQUIRED) == 0) { + requiredStmt(cf); } else { return; } diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/resources/jstat_options b/src/jdk.jcmd/share/classes/sun/tools/jstat/resources/jstat_options index 982dd9851f1..90032747e2b 100644 --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/resources/jstat_options +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/resources/jstat_options @@ -277,6 +277,7 @@ option gc { width 8 scale sec format "0.000" + required true } } @@ -537,6 +538,7 @@ option gccause { width 8 scale sec format "0.000" + required true } column { header "^LGCC" /* Last GC Cause */ @@ -835,6 +837,7 @@ option gcold { width 8 scale sec format "0.000" + required true } } @@ -917,6 +920,7 @@ option gcoldcapacity { width 8 scale sec format "0.000" + required true } } @@ -1015,6 +1019,7 @@ option gcmetacapacity { width 8 scale sec format "0.000" + required true } } @@ -1121,6 +1126,7 @@ option gcutil { width 8 scale sec format "0.000" + required true } } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 2695e729642..aa6e488e5e7 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -80,11 +80,6 @@ runtime/SharedArchiveFile/DefaultUseWithClient.java 8154204 generic-all serviceability/sa/TestRevPtrsForInvokeDynamic.java 8191270 generic-all serviceability/sa/sadebugd/SADebugDTest.java 8163805 generic-all -serviceability/tmtools/jstat/GcTest01.java 8199519 generic-all -serviceability/tmtools/jstat/GcTest02.java 8199519 generic-all -serviceability/tmtools/jstat/GcCauseTest01.java 8199519 generic-all -serviceability/tmtools/jstat/GcCauseTest02.java 8199519 generic-all -serviceability/tmtools/jstat/GcCauseTest03.java 8199519 generic-all ############################################################################# diff --git a/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java b/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java index 408abb66f1b..ed96a3a58cb 100644 --- a/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java +++ b/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java @@ -74,10 +74,18 @@ public class JstatGcCauseResults extends JstatResults { assertThat(GCT >= 0, "Incorrect time value for GCT"); assertThat(GCT >= YGCT, "GCT < YGCT (total garbage collection time < young generation garbage collection time)"); - int CGC = getIntValue("CGC"); - float CGCT = getFloatValue("CGCT"); - assertThat(CGCT >= 0, "Incorrect time value for CGCT"); + int CGC = 0; + float CGCT = 0.0f; + try { + CGC = getIntValue("CGC"); + } catch (NumberFormatException e) { + if (!e.getMessage().equals("Unparseable number: \"-\"")) { + throw e; + } + } if (CGC > 0) { + CGCT = getFloatValue("CGCT"); + assertThat(CGCT >= 0, "Incorrect time value for CGCT"); assertThat(CGCT > 0, "Number of concurrent GC events is " + CGC + ", but CGCT is 0"); } diff --git a/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcResults.java b/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcResults.java index 1c2c56700ca..dc725b68e85 100644 --- a/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcResults.java +++ b/test/hotspot/jtreg/serviceability/tmtools/jstat/utils/JstatGcResults.java @@ -103,10 +103,18 @@ public class JstatGcResults extends JstatResults { assertThat(GCT >= 0, "Incorrect time value for GCT"); assertThat(GCT >= YGCT, "GCT < YGCT (total garbage collection time < young generation garbage collection time)"); - int CGC = getIntValue("CGC"); - float CGCT = getFloatValue("CGCT"); - assertThat(CGCT >= 0, "Incorrect time value for CGCT"); + int CGC = 0; + float CGCT = 0.0f; + try { + CGC = getIntValue("CGC"); + } catch (NumberFormatException e) { + if (!e.getMessage().equals("Unparseable number: \"-\"")) { + throw e; + } + } if (CGC > 0) { + CGCT = getFloatValue("CGCT"); + assertThat(CGCT >= 0, "Incorrect time value for CGCT"); assertThat(CGCT > 0, "Number of concurrent GC events is " + CGC + ", but CGCT is 0"); } diff --git a/test/jdk/sun/tools/jstat/gcCapacityOutput1.awk b/test/jdk/sun/tools/jstat/gcCapacityOutput1.awk index d98da3a0bb4..351ec772f49 100644 --- a/test/jdk/sun/tools/jstat/gcCapacityOutput1.awk +++ b/test/jdk/sun/tools/jstat/gcCapacityOutput1.awk @@ -15,7 +15,7 @@ BEGIN { headerlines++; } -/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+$/ { +/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*(-|[0-9]+)$/ { datalines++; } diff --git a/test/jdk/sun/tools/jstat/gcMetaCapacityOutput1.awk b/test/jdk/sun/tools/jstat/gcMetaCapacityOutput1.awk index e0608e9a144..54d31bebda5 100644 --- a/test/jdk/sun/tools/jstat/gcMetaCapacityOutput1.awk +++ b/test/jdk/sun/tools/jstat/gcMetaCapacityOutput1.awk @@ -14,7 +14,7 @@ BEGIN { headerlines++; } -/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+$/ { +/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*(-|[0-9]+)[ ]*(-|[0-9]+\.[0-9]+)[ ]*[0-9]+\.[0-9]+$/ { datalines++; } diff --git a/test/jdk/sun/tools/jstat/gcNewCapacityOutput1.awk b/test/jdk/sun/tools/jstat/gcNewCapacityOutput1.awk index 8ae8dcacae7..378b787b661 100644 --- a/test/jdk/sun/tools/jstat/gcNewCapacityOutput1.awk +++ b/test/jdk/sun/tools/jstat/gcNewCapacityOutput1.awk @@ -15,7 +15,7 @@ BEGIN { headerlines++; } -/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+$/ { +/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*(-|[0-9]+)$/ { datalines++; } diff --git a/test/jdk/sun/tools/jstat/gcOldCapacityOutput1.awk b/test/jdk/sun/tools/jstat/gcOldCapacityOutput1.awk index aa8b68738b1..1534dbf2ffe 100644 --- a/test/jdk/sun/tools/jstat/gcOldCapacityOutput1.awk +++ b/test/jdk/sun/tools/jstat/gcOldCapacityOutput1.awk @@ -14,7 +14,7 @@ BEGIN { headerlines++; } -/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+$/ { +/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*(-|[0-9]+)[ ]*(-|[0-9]+\.[0-9]+)[ ]*[0-9]+\.[0-9]+$/ { datalines++; } diff --git a/test/jdk/sun/tools/jstat/gcOldOutput1.awk b/test/jdk/sun/tools/jstat/gcOldOutput1.awk index f37abfbd361..74f46cca56a 100644 --- a/test/jdk/sun/tools/jstat/gcOldOutput1.awk +++ b/test/jdk/sun/tools/jstat/gcOldOutput1.awk @@ -15,7 +15,7 @@ BEGIN { headerlines++; } -/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+$/ { +/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*(-|[0-9]+)[ ]*(-|[0-9]+\.[0-9]+)[ ]*[0-9]+\.[0-9]+$/ { datalines++; } diff --git a/test/jdk/sun/tools/jstat/gcOutput1.awk b/test/jdk/sun/tools/jstat/gcOutput1.awk index a07e2d487b8..10764ae2e2c 100644 --- a/test/jdk/sun/tools/jstat/gcOutput1.awk +++ b/test/jdk/sun/tools/jstat/gcOutput1.awk @@ -15,7 +15,7 @@ BEGIN { headerlines++; } -/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+$/ { +/^[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*[0-9]+[ ]*[0-9]+\.[0-9]+[ ]*(-|[0-9]+)[ ]*(-|[0-9]+\.[0-9]+)[ ]*[0-9]+\.[0-9]+$/ { datalines++; } From 408c9720773183df9b20c4e2eaacf5290438f9e8 Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Wed, 25 Apr 2018 18:30:38 -0700 Subject: [PATCH 047/102] 8202154: Remove unused code in java.base/windows/native/libnet Reviewed-by: vtewari, clanger --- .../net/DualStackPlainDatagramSocketImpl.java | 6 +- .../windows/classes/sun/net/PortConfig.java | 40 +-- .../libnet/DualStackPlainDatagramSocketImpl.c | 11 +- .../libnet/TwoStacksPlainDatagramSocketImpl.c | 267 ++---------------- .../windows/native/libnet/net_util_md.c | 71 +---- .../windows/native/libnet/net_util_md.h | 7 +- .../windows/native/libnet/portconfig.c | 107 ------- 7 files changed, 35 insertions(+), 474 deletions(-) delete mode 100644 src/java.base/windows/native/libnet/portconfig.c diff --git a/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java b/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java index 294cd5985bf..3363f388188 100644 --- a/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java +++ b/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl if (fd == null) throw new SocketException("Socket closed"); - int newfd = socketCreate(false /* v6Only */); + int newfd = socketCreate(); fdAccess.set(fd, newfd); } @@ -274,7 +274,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl private static native void initIDs(); - private static native int socketCreate(boolean v6Only); + private static native int socketCreate(); private static native void socketBind(int fd, InetAddress localAddress, int localport, boolean exclBind) throws SocketException; diff --git a/src/java.base/windows/classes/sun/net/PortConfig.java b/src/java.base/windows/classes/sun/net/PortConfig.java index 9749b7e418d..9a1b61198ff 100644 --- a/src/java.base/windows/classes/sun/net/PortConfig.java +++ b/src/java.base/windows/classes/sun/net/PortConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,49 +25,21 @@ package sun.net; -import java.security.AccessController; - /** * Determines the ephemeral port range in use on this system. - * If this cannot be determined, then the default settings - * of the OS are returned. + * On Windows we always use the default range. */ public final class PortConfig { - private static int defaultUpper, defaultLower; - private static final int upper, lower; - - static { - AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - System.loadLibrary("net"); - return null; - } - }); - - int v = getLower0(); - if (v == -1) { - v = defaultLower; - } - lower = v; - - v = getUpper0(); - if (v == -1) { - v = defaultUpper; - } - upper = v; - } - - static native int getLower0(); - static native int getUpper0(); + private static final int defaultLower = 49152; + private static final int defaultUpper = 65535; public static int getLower() { - return lower; + return defaultLower; } public static int getUpper() { - return upper; + return defaultUpper; } } diff --git a/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c b/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c index 90f3c1f7318..210431037ac 100644 --- a/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c +++ b/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,10 +92,10 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_initIDs /* * Class: java_net_DualStackPlainDatagramSocketImpl * Method: socketCreate - * Signature: (Z)I + * Signature: ()I */ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCreate - (JNIEnv *env, jclass clazz, jboolean v6Only /*unused*/) { + (JNIEnv *env, jclass clazz) { int fd, rv, opt=0, t=TRUE; DWORD x1, x2; /* ignored result codes */ @@ -121,7 +121,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCrea * when the socket is connected. */ t = FALSE; - WSAIoctl(fd ,SIO_UDP_CONNRESET ,&t ,sizeof(t) ,&x1 ,sizeof(x1) ,&x2 ,0 ,0); + WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0); return fd; } @@ -158,7 +158,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConnect (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { SOCKETADDRESS sa; - int rv, sa_len = 0, t = TRUE; + int rv, sa_len = 0, t; DWORD x1, x2; /* ignored result codes */ if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, @@ -173,6 +173,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConn } /* see comment in socketCreate */ + t = TRUE; WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0); } diff --git a/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c b/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c index f60f0252a71..e8f22ec0218 100644 --- a/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c +++ b/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c @@ -63,13 +63,6 @@ jfieldID pdsi_connected; static jclass ia4_clazz; static jmethodID ia4_ctor; -static CRITICAL_SECTION sizeCheckLock; - -/* Windows OS version is XP or better */ -static int xp_or_later = 0; -/* Windows OS version is Windows 2000 or better */ -static int w2k_or_later = 0; - /* * Notes about UDP/IPV6 on Windows (XP and 2003 server): * @@ -136,182 +129,6 @@ static int getFD1(JNIEnv *env, jobject this) { return (*env)->GetIntField(env, fdObj, IO_fd_fdID); } -/* - * This function returns JNI_TRUE if the datagram size exceeds the underlying - * provider's ability to send to the target address. The following OS - * oddities have been observed :- - * - * 1. On Windows 95/98 if we try to send a datagram > 12k to an application - * on the same machine then the send will fail silently. - * - * 2. On Windows ME if we try to send a datagram > supported by underlying - * provider then send will not return an error. - * - * 3. On Windows NT/2000 if we exceeds the maximum size then send will fail - * with WSAEADDRNOTAVAIL. - * - * 4. On Windows 95/98 if we exceed the maximum size when sending to - * another machine then WSAEINVAL is returned. - * - */ -jboolean exceedSizeLimit(JNIEnv *env, jint fd, jint addr, jint size) -{ -#define DEFAULT_MSG_SIZE 65527 - static jboolean initDone; - static jboolean is95or98; - static int maxmsg; - - typedef struct _netaddr { /* Windows 95/98 only */ - unsigned long addr; - struct _netaddr *next; - } netaddr; - static netaddr *addrList; - netaddr *curr; - - /* - * First time we are called we must determine which OS this is and also - * get the maximum size supported by the underlying provider. - * - * In addition on 95/98 we must enumerate our IP addresses. - */ - if (!initDone) { - EnterCriticalSection(&sizeCheckLock); - - if (initDone) { - /* another thread got there first */ - LeaveCriticalSection(&sizeCheckLock); - - } else { - OSVERSIONINFO ver; - int len; - - /* - * Step 1: Determine which OS this is. - */ - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - - is95or98 = JNI_FALSE; - if (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && - ver.dwMajorVersion == 4 && - (ver.dwMinorVersion == 0 || ver.dwMinorVersion == 10)) { - - is95or98 = JNI_TRUE; - } - - /* - * Step 2: Determine the maximum datagram supported by the - * underlying provider. On Windows 95 if winsock hasn't been - * upgraded (ie: unsupported configuration) then we assume - * the default 64k limit. - */ - len = sizeof(maxmsg); - if (NET_GetSockOpt(fd, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&maxmsg, &len) < 0) { - maxmsg = DEFAULT_MSG_SIZE; - } - - /* - * Step 3: On Windows 95/98 then enumerate the IP addresses on - * this machine. This is neccesary because we need to check if the - * datagram is being sent to an application on the same machine. - */ - if (is95or98) { - char hostname[255]; - struct hostent *hp; - - if (gethostname(hostname, sizeof(hostname)) == -1) { - LeaveCriticalSection(&sizeCheckLock); - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unable to obtain hostname"); - return JNI_TRUE; - } - hp = (struct hostent *)gethostbyname(hostname); - if (hp != NULL) { - struct in_addr **addrp = (struct in_addr **) hp->h_addr_list; - - while (*addrp != (struct in_addr *) 0) { - curr = (netaddr *)malloc(sizeof(netaddr)); - if (curr == NULL) { - while (addrList != NULL) { - curr = addrList->next; - free(addrList); - addrList = curr; - } - LeaveCriticalSection(&sizeCheckLock); - JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); - return JNI_TRUE; - } - curr->addr = htonl((*addrp)->S_un.S_addr); - curr->next = addrList; - addrList = curr; - addrp++; - } - } - } - - /* - * Step 4: initialization is done so set flag and unlock cs - */ - initDone = JNI_TRUE; - LeaveCriticalSection(&sizeCheckLock); - } - } - - /* - * Now examine the size of the datagram :- - * - * (a) If exceeds size of service provider return 'false' to indicate that - * we exceed the limit. - * (b) If not 95/98 then return 'true' to indicate that the size is okay. - * (c) On 95/98 if the size is <12k we are okay. - * (d) On 95/98 if size > 12k then check if the destination is the current - * machine. - */ - if (size > maxmsg) { /* step (a) */ - return JNI_TRUE; - } - if (!is95or98) { /* step (b) */ - return JNI_FALSE; - } - if (size <= 12280) { /* step (c) */ - return JNI_FALSE; - } - - /* step (d) */ - - if ((addr & 0x7f000000) == 0x7f000000) { - return JNI_TRUE; - } - curr = addrList; - while (curr != NULL) { - if (curr->addr == addr) { - return JNI_TRUE; - } - curr = curr->next; - } - return JNI_FALSE; -} - -/* - * Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable - */ -__inline static jboolean supportPortUnreachable() { - static jboolean initDone; - static jboolean portUnreachableSupported; - - if (!initDone) { - OSVERSIONINFO ver; - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 5) { - portUnreachableSupported = JNI_TRUE; - } else { - portUnreachableSupported = JNI_FALSE; - } - initDone = JNI_TRUE; - } - return portUnreachableSupported; -} - /* * This function "purges" all outstanding ICMP port unreachable packets * outstanding on a socket and returns JNI_TRUE if any ICMP messages @@ -330,13 +147,6 @@ static jboolean purgeOutstandingICMP(JNIEnv *env, jobject this, jint fd) memset((char *)&rmtaddr, 0, sizeof(rmtaddr)); - /* - * A no-op if this OS doesn't support it. - */ - if (!supportPortUnreachable()) { - return JNI_FALSE; - } - /* * Peek at the queue to see if there is an ICMP port unreachable. If there * is then receive it. @@ -370,16 +180,6 @@ static jboolean purgeOutstandingICMP(JNIEnv *env, jobject this, jint fd) */ JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { - - OSVERSIONINFO ver; - int version; - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - - version = ver.dwMajorVersion * 10 + ver.dwMinorVersion; - xp_or_later = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (version >= 51); - w2k_or_later = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (version >= 50); - /* get fieldIDs */ pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;"); CHECK_NULL(pdsi_fdID); @@ -409,9 +209,6 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { CHECK_NULL(ia4_clazz); ia4_ctor = (*env)->GetMethodID(env, ia4_clazz, "", "()V"); CHECK_NULL(ia4_ctor); - - - InitializeCriticalSection(&sizeCheckLock); } JNIEXPORT void JNICALL @@ -524,6 +321,8 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0 jint fd = -1, fd1 = -1, fdc, family; SOCKETADDRESS rmtaddr; int rmtaddrlen = 0; + DWORD x1, x2; /* ignored result codes */ + int res, t; if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -553,16 +352,13 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0 fdc = family == java_net_InetAddress_IPv4 ? fd : fd1; - if (xp_or_later) { - /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which - * returns connection reset errors on connected UDP sockets (as well - * as connected sockets). The solution is to only enable this feature - * when the socket is connected - */ - DWORD x1, x2; /* ignored result codes */ - int res, t = TRUE; - res = WSAIoctl(fdc,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0); - } + /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which + * returns connection reset errors on connected UDP sockets (as well + * as connected sockets). The solution is to only enable this feature + * when the socket is connected + */ + t = TRUE; + res = WSAIoctl(fdc, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0); if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr, &rmtaddrlen, JNI_FALSE) != 0) { @@ -588,6 +384,8 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject /* The fdObj'fd */ jint fd, len; SOCKETADDRESS addr; + DWORD x1 = 0, x2 = 0; /* ignored result codes */ + int t; if (family == java_net_InetAddress_IPv4) { fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); @@ -610,11 +408,8 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject * use SIO_UDP_CONNRESET * to disable ICMP port unreachable handling here. */ - if (xp_or_later) { - DWORD x1 = 0, x2 = 0; /* ignored result codes */ - int t = FALSE; - WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0); - } + t = FALSE; + WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0); } /* @@ -632,7 +427,6 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_send jint fd; jobject iaObj; - jint address; jint family; jint packetBufferOffset, packetBufferLen, packetPort; @@ -697,32 +491,6 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_send } if (packetBufferLen > MAX_BUFFER_LEN) { - - /* - * On 95/98 if we try to send a datagram >12k to an application - * on the same machine then this will fail silently. Thus we - * catch this situation here so that we can throw an exception - * when this arises. - * On ME if we try to send a datagram with a size greater than - * that supported by the service provider then no error is - * returned. - */ - if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6. - * Check is not necessary on these OSes */ - if (connected) { - address = getInetAddress_addr(env, iaObj); - } else { - address = ntohl(rmtaddr.sa4.sin_addr.s_addr); - } - - if (exceedSizeLimit(env, fd, address, packetBufferLen)) { - if (!((*env)->ExceptionOccurred(env))) { - NET_ThrowNew(env, WSAEMSGSIZE, "Datagram send failed"); - } - return; - } - } - /* When JNI-ifying the JDK's IO routines, we turned * reads and writes of byte arrays of size greater * than 2048 bytes into several operations of size 2048. @@ -1282,16 +1050,15 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_receive0(JNIEnv *env, jobject thi /* - * If this Windows edition supports ICMP port unreachable and if we - * are not connected then we need to know if a timeout has been specified - * and if so we need to pick up the current time. These are required in - * order to implement the semantics of timeout, viz :- + * If we are not connected then we need to know if a timeout has been + * specified and if so we need to pick up the current time. These are + * required in order to implement the semantics of timeout, viz :- * timeout set to t1 but ICMP port unreachable arrives in t2 where * t2 < t1. In this case we must discard the ICMP packets and then * wait for the next packet up to a maximum of t1 minus t2. */ connected = (*env)->GetBooleanField(env, this, pdsi_connected); - if (supportPortUnreachable() && !connected && timeout &&!ipv6_supported) { + if (!connected && timeout && !ipv6_supported) { prevTime = JVM_CurrentTimeMillis(env, 0); } diff --git a/src/java.base/windows/native/libnet/net_util_md.c b/src/java.base/windows/native/libnet/net_util_md.c index 68bde179cd9..7045b46e007 100644 --- a/src/java.base/windows/native/libnet/net_util_md.c +++ b/src/java.base/windows/native/libnet/net_util_md.c @@ -227,73 +227,9 @@ jint IPv6_supported() jint reuseport_supported() { - /* SO_REUSEPORT is not supported onn Windows */ + /* SO_REUSEPORT is not supported on Windows */ return JNI_FALSE; } -/* - * Return the default TOS value - */ -int NET_GetDefaultTOS() { - static int default_tos = -1; - OSVERSIONINFO ver; - HKEY hKey; - LONG ret; - - /* - * If default ToS already determined then return it - */ - if (default_tos >= 0) { - return default_tos; - } - - /* - * Assume default is "normal service" - */ - default_tos = 0; - - /* - * Which OS is this? - */ - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - - /* - * If 2000 or greater then no default ToS in registry - */ - if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - if (ver.dwMajorVersion >= 5) { - return default_tos; - } - } - - /* - * Query the registry to see if a Default ToS has been set. - * Different registry entry for NT vs 95/98/ME. - */ - if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - "SYSTEM\\CurrentControlSet\\Services\\Tcp\\Parameters", - 0, KEY_READ, (PHKEY)&hKey); - } else { - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP\\Parameters", - 0, KEY_READ, (PHKEY)&hKey); - } - if (ret == ERROR_SUCCESS) { - DWORD dwLen; - DWORD dwDefaultTOS; - ULONG ulType; - dwLen = sizeof(dwDefaultTOS); - - ret = RegQueryValueEx(hKey, "DefaultTOS", NULL, &ulType, - (LPBYTE)&dwDefaultTOS, &dwLen); - RegCloseKey(hKey); - if (ret == ERROR_SUCCESS) { - default_tos = (int)dwDefaultTOS; - } - } - return default_tos; -} /* call NET_MapSocketOptionV6 for the IPv6 fd only * and NET_MapSocketOption for the IPv4 fd @@ -454,10 +390,7 @@ NET_GetSockOpt(int s, int level, int optname, void *optval, if (WSAGetLastError() == WSAENOPROTOOPT && level == IPPROTO_IP && optname == IP_TOS) { - int *tos; - tos = (int *)optval; - *tos = NET_GetDefaultTOS(); - + *((int *)optval) = 0; rv = 0; } } diff --git a/src/java.base/windows/native/libnet/net_util_md.h b/src/java.base/windows/native/libnet/net_util_md.h index 26a9e38022a..2edf008d181 100644 --- a/src/java.base/windows/native/libnet/net_util_md.h +++ b/src/java.base/windows/native/libnet/net_util_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,11 +52,6 @@ extern jboolean isRcvTimeoutSupported; void NET_ThrowCurrent(JNIEnv *env, char *msg); -/* - * Return default Type Of Service - */ -int NET_GetDefaultTOS(void); - typedef union { struct sockaddr sa; struct sockaddr_in sa4; diff --git a/src/java.base/windows/native/libnet/portconfig.c b/src/java.base/windows/native/libnet/portconfig.c deleted file mode 100644 index f786ef7b511..00000000000 --- a/src/java.base/windows/native/libnet/portconfig.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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. - */ - -#include -#include "jni.h" -#include "net_util.h" -#include "sun_net_PortConfig.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct portrange { - int lower; - int higher; -}; - -static int getPortRange(struct portrange *range) -{ - OSVERSIONINFO ver; - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - - /* Check for major version 5 or less = Windows XP/2003 or older */ - if (ver.dwMajorVersion <= 5) { - LONG ret; - HKEY hKey; - range->lower = 1024; - range->higher = 4999; - - /* check registry to see if upper limit was raised */ - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", - 0, KEY_READ, (PHKEY)&hKey - ); - if (ret == ERROR_SUCCESS) { - DWORD maxuserport; - ULONG ulType; - DWORD dwLen = sizeof(maxuserport); - ret = RegQueryValueEx(hKey, "MaxUserPort", NULL, &ulType, - (LPBYTE)&maxuserport, &dwLen); - RegCloseKey(hKey); - if (ret == ERROR_SUCCESS) { - range->higher = maxuserport; - } - } - } else { - /* There doesn't seem to be an API to access this. "MaxUserPort" - * is affected, but is not sufficient to determine. - * so we just use the defaults, which are less likely to change - */ - range->lower = 49152; - range->higher = 65535; - } - return 0; -} - -/* - * Class: sun_net_PortConfig - * Method: getLower0 - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_net_PortConfig_getLower0 - (JNIEnv *env, jclass clazz) -{ - struct portrange range; - getPortRange(&range); - return range.lower; -} - -/* - * Class: sun_net_PortConfig - * Method: getUpper0 - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_sun_net_PortConfig_getUpper0 - (JNIEnv *env, jclass clazz) -{ - struct portrange range; - getPortRange(&range); - return range.higher; -} -#ifdef __cplusplus -} -#endif From 673e292ffeaedf10d71bc179ec9bc847e938deae Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 26 Apr 2018 10:29:44 +0800 Subject: [PATCH 048/102] 8157543: java/nio/channels/Selector/SelectAndCancel.java fails intermittently Reviewed-by: alanb --- .../channels/Selector/SelectAndCancel.java | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/test/jdk/java/nio/channels/Selector/SelectAndCancel.java b/test/jdk/java/nio/channels/Selector/SelectAndCancel.java index dc28480a76c..229048179ed 100644 --- a/test/jdk/java/nio/channels/Selector/SelectAndCancel.java +++ b/test/jdk/java/nio/channels/Selector/SelectAndCancel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,65 +23,61 @@ /* @test * @bug 4729342 + * @library /test/lib + * @build jdk.test.lib.Utils + * @run main SelectAndCancel * @summary Check for CancelledKeyException when key cancelled during select */ -import java.nio.channels.*; -import java.io.IOException; -import java.net.*; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.util.concurrent.CountDownLatch; public class SelectAndCancel { - static SelectionKey sk; + static volatile SelectionKey sk; + static volatile Throwable ex; /* * CancelledKeyException is the failure symptom of 4729342 * NOTE: The failure is timing dependent and is not always * seen immediately when the bug is present. */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Throwable { final Selector selector = Selector.open(); - final ServerSocketChannel ssc = - ServerSocketChannel.open().bind(new InetSocketAddress(0)); - final InetSocketAddress isa = - new InetSocketAddress(InetAddress.getLocalHost(), ssc.socket().getLocalPort()); + final ServerSocketChannel ssc = ServerSocketChannel.open().bind( + new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + final InetSocketAddress isa = (InetSocketAddress)ssc.getLocalAddress(); + final CountDownLatch signal = new CountDownLatch(1); // Create and start a selector in a separate thread. - new Thread(new Runnable() { + Thread t = new Thread(new Runnable() { public void run() { try { ssc.configureBlocking(false); sk = ssc.register(selector, SelectionKey.OP_ACCEPT); + signal.countDown(); selector.select(); - } catch (IOException e) { - System.err.println("error in selecting thread"); - e.printStackTrace(); + } catch (Throwable e) { + ex = e; } } - }).start(); + }); + t.start(); - // Wait for above thread to get to select() before we call close. - Thread.sleep(3000); + signal.await(); + // Wait for above thread to get to select() before we call cancel. + Thread.sleep((long)(300 * jdk.test.lib.Utils.TIMEOUT_FACTOR)); - // Try to close. This should wakeup select. - new Thread(new Runnable() { - public void run() { - try { - SocketChannel sc = SocketChannel.open(); - sc.connect(isa); - ssc.close(); - sk.cancel(); - sc.close(); - } catch (IOException e) { - System.err.println("error in closing thread"); - System.err.println(e); - } - } - }).start(); - - // Wait for select() to be awakened, which should be done by close. - Thread.sleep(3000); - - selector.wakeup(); + // CancelledKeyException should not be thrown. + ssc.close(); + sk.cancel(); selector.close(); + t.join(); + if (ex != null) { + throw ex; + } } } From 1515d709305a91729edcf08e0e060182c0f2d66a Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Wed, 25 Apr 2018 14:08:19 -0700 Subject: [PATCH 049/102] 8197959: [TESTBUG] Some (App)CDS tests require modification due to the removal of the Java EE and CORBA modules Reviewed-by: iklam, mseledtsov --- test/hotspot/jtreg/ProblemList.txt | 6 - .../SharedArchiveFile/BootAppendTests.java | 119 +++++++++++------- .../processing/FilerException.jasm} | 6 +- .../jtreg/runtime/appcds/HelloExtTest.java | 8 +- .../javaldr/AnonVmClassesDuringDump.java | 16 ++- .../appcds/javaldr/CheckAnonymousClass.java | 65 ---------- .../classpathtests/BootAppendTests.java | 8 +- .../jigsaw/classpathtests/ClassPathTests.java | 114 +++++++++-------- .../DummyClassesInBootClassPath.java | 19 ++- .../tools/javac/{Main2.jasm => MyMain.jasm} | 4 +- .../UnsupportedDataTypeException2.jasm | 46 ------- .../classpathtests/src/jdk/test/Main.java | 12 +- .../jigsaw/overridetests/OverrideTests.java | 82 +++++------- .../java/net/http/HttpTimeoutException.java} | 11 +- .../module-info.java | 4 +- .../overridetests/src/test/jdk/test/Main.java | 12 +- .../overridetests/src/test/module-info.java | 4 +- .../runtime/appcds/test-classes/HelloExt.java | 4 +- .../javax/activation/MimeType.jasm | 37 ------ test/lib/jdk/test/lib/cds/CDSTestUtils.java | 4 + 20 files changed, 226 insertions(+), 355 deletions(-) rename test/hotspot/jtreg/runtime/SharedArchiveFile/{org/omg/CORBA/Context.jasm => javax/annotation/processing/FilerException.jasm} (90%) delete mode 100644 test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java rename test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/{Main2.jasm => MyMain.jasm} (93%) delete mode 100644 test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/javax/activation/UnsupportedDataTypeException2.jasm rename test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/{java.activation/javax/activation/UnsupportedDataTypeException.java => java.net.http/java/net/http/HttpTimeoutException.java} (80%) rename test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/{java.activation => java.net.http}/module-info.java (95%) delete mode 100644 test/hotspot/jtreg/runtime/appcds/test-classes/javax/activation/MimeType.jasm diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index aa6e488e5e7..d1e90578a00 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -92,12 +92,6 @@ serviceability/sa/sadebugd/SADebugDTest.java 8163805 generic-all # Java EE Module Removal # -runtime/appcds/jigsaw/classpathtests/ClassPathTests.java 8194310 generic-all Java EE Module Removal -runtime/appcds/jigsaw/overridetests/OverrideTests.java 8194310 generic-all Java EE Module Removal -runtime/SharedArchiveFile/BootAppendTests.java 8194310 generic-all Java EE Module Removal runtime/modules/PatchModule/PatchModuleClassList.java 8194310 generic-all Java EE Module Removal compiler/c2/Test8007294.java 8194310 generic-all Java EE Module Removal compiler/c2/Test6852078.java 8194310 generic-all Java EE Module Removal -runtime/AppCDS/HelloExtTest.java 8194310 generic-all Java EE Module Removal -runtime/AppCDS/javaldr/CheckAnonymousClass.java 8194310 generic-all Java EE Module Removal -runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java 8194310 generic-all Java EE Module Removal diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java index 22c9da4b09c..7a728a9b458 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,12 @@ * @summary Testing -Xbootclasspath/a support for CDS * @requires vm.cds * @library /test/lib - * @modules java.base/jdk.internal.misc + * @modules java.compiler + * java.base/jdk.internal.misc * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor * @compile javax/sound/sampled/MyClass.jasm - * @compile org/omg/CORBA/Context.jasm + * @compile javax/annotation/processing/FilerException.jasm * @compile nonjdk/myPackage/MyClass.java * @build LoadClass * @run main/othervm BootAppendTests @@ -53,7 +54,8 @@ import jdk.test.lib.process.OutputAnalyzer; public class BootAppendTests { private static final String APP_CLASS = "LoadClass"; private static final String BOOT_APPEND_MODULE_CLASS = "javax/sound/sampled/MyClass"; - private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS = "org/omg/CORBA/Context"; + private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS = + "javax/annotation/processing/FilerException"; private static final String BOOT_APPEND_CLASS = "nonjdk/myPackage/MyClass"; private static final String BOOT_APPEND_MODULE_CLASS_NAME = BOOT_APPEND_MODULE_CLASS.replace('/', '.'); @@ -141,21 +143,21 @@ public class BootAppendTests { // from -Xbootclasspath/a. Verify the behavior is the same at runtime // when CDS is enabled. // - // The org.omg.CORBA.Context is a boot module class. The class on - // the -Xbootclasspath/a path that has the same fully-qualified name - // should not be loaded at runtime when CDS is enabled. - // The one from the boot modules should be loaded instead. + // The javax/annotation/processing/FilerException is a platform module + // class. The class on the -Xbootclasspath/a path that has the same + // fully-qualified name should not be loaded at runtime when CDS is enabled. + // The one from the platform modules should be loaded instead. public static void testBootAppendDuplicateModuleClass() throws Exception { for (String mode : modes) { CDSOptions opts = (new CDSOptions()) .setXShareMode(mode).setUseVersion(false) - .addPrefix("--add-modules", "java.corba", "-showversion", + .addPrefix("-showversion", "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar) .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); - CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context source: jrt:/java.corba"); + CDSTestUtils.checkExec(out, opts, "[class,load] javax.annotation.processing.FilerException source: jrt:/java.compiler"); } } @@ -164,9 +166,9 @@ public class BootAppendTests { // using --limit-modules. Verify the behavior is the same at runtime when CDS // is enabled. // - // The java.desktop module is excluded using --limit-modules at runtime, - // javax.sound.sampled.MyClass is archived from -Xbootclasspath/a. It can be - // loaded from the archive at runtime. + // The java.desktop module is excluded using --limit-modules at runtime + // CDS will be disabled with the --limit-modules option during runtime. + // javax.sound.sampled.MyClass will be loaded from the jar at runtime. public static void testBootAppendExcludedModuleClass() throws Exception { for (String mode : modes) { CDSOptions opts = (new CDSOptions()) @@ -175,13 +177,18 @@ public class BootAppendTests { "--limit-modules=java.base", "-cp", appJar) .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); - - OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); - CDSTestUtils.checkExec(out, opts, "[class,load] javax.sound.sampled.MyClass"); - - // When CDS is enabled, the shared class should be loaded from the archive. + CDSTestUtils.Result res = CDSTestUtils.run(opts); + String MATCH_PATTERN = + ".class.load. javax.sound.sampled.MyClass source:.*bootAppend.jar*"; if (mode.equals("on")) { - CDSTestUtils.checkExec(out, opts, "[class,load] javax.sound.sampled.MyClass source: shared objects file"); + res.assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0) + .shouldMatch(MATCH_PATTERN); + }); + } else { + res.assertNormalExit(out -> { + out.shouldMatch(MATCH_PATTERN); + }); } } } @@ -192,10 +199,12 @@ public class BootAppendTests { // --limit-modules. Verify the behavior is the same at runtime // when CDS is enabled. // - // The org.omg.CORBA.Context is a boot module class. The class - // on -Xbootclasspath/a that has the same fully-qualified name - // as org.omg.CORBA.Context can be loaded at runtime when - // java.corba is excluded. + // The javax.annotation.processing.FilerException is a platform module class. + // The class on -Xbootclasspath/a that has the same fully-qualified name + // as javax.annotation.processing.FilerException can be loaded at runtime when + // java.compiler is excluded. + // CDS is disabled during runtime if the --limit-modules option is + // specified. public static void testBootAppendDuplicateExcludedModuleClass() throws Exception { for (String mode : modes) { CDSOptions opts = (new CDSOptions()) @@ -205,14 +214,18 @@ public class BootAppendTests { .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); - OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); - CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context"); - if (!CDSTestUtils.isUnableToMap(out)) { - if (mode.equals("off")) { - out.shouldMatch(".*\\[class,load\\] org.omg.CORBA.Context source:.*bootAppend.jar"); - } else { - CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context source: shared objects file"); - } + CDSTestUtils.Result res = CDSTestUtils.run(opts); + String MATCH_PATTERN = + ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; + if (mode.equals("on")) { + res.assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0) + .shouldMatch(MATCH_PATTERN); + }); + } else { + res.assertNormalExit(out -> { + out.shouldMatch(MATCH_PATTERN); + }); } } } @@ -222,8 +235,9 @@ public class BootAppendTests { // the same at runtime when CDS is enabled. // // The nonjdk.myPackage is not defined in named modules. The - // archived nonjdk.myPackage.MyClass from -Xbootclasspath/a - // can be loaded at runtime when CDS is enabled. + // nonjdk.myPackage.MyClass will be loaded from the jar in + // -Xbootclasspath/a since CDS will be disabled with the + // --limit-modules option. public static void testBootAppendClass() throws Exception { for (String mode : modes) { CDSOptions opts = (new CDSOptions()) @@ -233,21 +247,26 @@ public class BootAppendTests { .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_CLASS_NAME); - OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); - CDSTestUtils.checkExec(out, opts, "[class,load] nonjdk.myPackage.MyClass"); - - // If CDS is enabled, the nonjdk.myPackage.MyClass should be loaded - // from the shared archive. + CDSTestUtils.Result res = CDSTestUtils.run(opts); + String MATCH_PATTERN = + ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; if (mode.equals("on")) { - CDSTestUtils.checkExec(out, opts, - "[class,load] nonjdk.myPackage.MyClass source: shared objects file"); + res.assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0) + .shouldMatch(MATCH_PATTERN); + }); + } else { + res.assertNormalExit(out -> { + out.shouldMatch(MATCH_PATTERN); + }); } } } // Test #6: This is similar to Test #5. During runtime, an extra dir // is appended to the bootclasspath. It should not invalidate - // the shared archive. + // the shared archive. However, CDS will be disabled with the + // --limit-modules in the command line. public static void testBootAppendExtraDir() throws Exception { for (String mode : modes) { CDSOptions opts = (new CDSOptions()) @@ -257,14 +276,18 @@ public class BootAppendTests { .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_CLASS_NAME); - OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); - CDSTestUtils.checkExec(out, opts, "[class,load] nonjdk.myPackage.MyClass"); - - // If CDS is enabled, the nonjdk.myPackage.MyClass should be loaded - // from the shared archive. + CDSTestUtils.Result res = CDSTestUtils.run(opts); + String MATCH_PATTERN = + ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; if (mode.equals("on")) { - CDSTestUtils.checkExec(out, opts, - "[class,load] nonjdk.myPackage.MyClass source: shared objects file"); + res.assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0) + .shouldMatch(MATCH_PATTERN); + }); + } else { + res.assertNormalExit(out -> { + out.shouldMatch(MATCH_PATTERN); + }); } } } diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/org/omg/CORBA/Context.jasm b/test/hotspot/jtreg/runtime/SharedArchiveFile/javax/annotation/processing/FilerException.jasm similarity index 90% rename from test/hotspot/jtreg/runtime/SharedArchiveFile/org/omg/CORBA/Context.jasm rename to test/hotspot/jtreg/runtime/SharedArchiveFile/javax/annotation/processing/FilerException.jasm index c3424b9f799..e34d2542b09 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/org/omg/CORBA/Context.jasm +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/javax/annotation/processing/FilerException.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,9 @@ * questions. */ -package org/omg/CORBA; +package javax/annotation/processing; -public class Context +public class FilerException version 51:0 { diff --git a/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java b/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java index 0090164e6ea..489dabd0231 100644 --- a/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java +++ b/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java @@ -51,8 +51,8 @@ public class HelloExtTest { String bootClassPath = "-Xbootclasspath/a:" + whiteBoxJar; TestCommon.dump(appJar, - TestCommon.list("org/omg/CORBA/ORB", "[Ljava/lang/Comparable;"), - bootClassPath, "-verbose:class", "--add-modules", "java.corba"); + TestCommon.list("javax/annotation/processing/FilerException", "[Ljava/lang/Comparable;"), + bootClassPath, "-verbose:class"); String prefix = ".class.load. "; String class_pattern = ".*LambdaForm[$]MH[/][0123456789].*"; @@ -60,14 +60,14 @@ public class HelloExtTest { String pattern = prefix + class_pattern + suffix; TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "-cp", appJar, bootClassPath, "-verbose:class", "--add-modules", "java.corba", "HelloExt") + "-cp", appJar, bootClassPath, "-verbose:class", "HelloExt") .assertNormalExit(output -> output.shouldNotMatch(pattern)); TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-cp", appJar, bootClassPath, "-verbose:class", "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary", - "--add-modules", "java.corba", "HelloExt") + "HelloExt") .assertNormalExit(output -> output.shouldNotMatch(class_pattern)); } } diff --git a/test/hotspot/jtreg/runtime/appcds/javaldr/AnonVmClassesDuringDump.java b/test/hotspot/jtreg/runtime/appcds/javaldr/AnonVmClassesDuringDump.java index 630966104c2..0bc0ff1e0fa 100644 --- a/test/hotspot/jtreg/runtime/appcds/javaldr/AnonVmClassesDuringDump.java +++ b/test/hotspot/jtreg/runtime/appcds/javaldr/AnonVmClassesDuringDump.java @@ -61,8 +61,22 @@ public class AnonVmClassesDuringDump { // Set the following property to see logs for dynamically generated classes // in STDOUT "-Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true"); + + String prefix = ".class.load. "; + // class name pattern like the following: + // jdk.internal.loader.BuiltinClassLoader$$Lambda$1/1816757085 + // java.lang.invoke.LambdaForm$MH/1585787493 + String class_pattern = ".*Lambda([a-z0-9$]+)/([0-9]+).*"; + String suffix = ".*source: shared objects file.*"; + String pattern = prefix + class_pattern + suffix; + // during run time, anonymous classes shouldn't be loaded from the archive TestCommon.run("-cp", appJar, "Hello") - .assertNormalExit(); + .assertNormalExit(output -> output.shouldNotMatch(pattern)); + + // inspect the archive and make sure no anonymous class is in there + TestCommon.run("-cp", appJar, + "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary", "Hello") + .assertNormalExit(output -> output.shouldNotMatch(class_pattern)); } } diff --git a/test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java b/test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java deleted file mode 100644 index c1c6b6b0793..00000000000 --- a/test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * @test - * @summary ensure no anonymous class is being dumped into the CDS archive - * @requires vm.cds - * @library /test/lib /test/hotspot/jtreg/runtime/appcds - * @modules jdk.jartool/sun.tools.jar - * @compile ../test-classes/Hello.java - * @run main CheckAnonymousClass - */ - -import jdk.test.lib.process.OutputAnalyzer; - -public class CheckAnonymousClass { - - public static void main(String[] args) throws Exception { - JarBuilder.build("hello", "Hello"); - - String appJar = TestCommon.getTestJar("hello.jar"); - - TestCommon.dump(appJar, TestCommon.list("Hello", "org/omg/CORBA/ORB"), - "--add-modules", "java.corba", "-Xlog:class+load=info"); - - String prefix = ".class.load. "; - // class name pattern like the following: - // jdk.internal.loader.BuiltinClassLoader$$Lambda$1/1816757085 - // java.lang.invoke.LambdaForm$MH/1585787493 - String class_pattern = ".*Lambda([a-z0-9$]+)/([0-9]+).*"; - String suffix = ".*source: shared objects file.*"; - String pattern = prefix + class_pattern + suffix; - // during run time, anonymous classes shouldn't be loaded from the archive - TestCommon.run("-XX:+UnlockDiagnosticVMOptions", - "-cp", appJar, "-Xlog:class+load=info", "--add-modules", "java.corba", "Hello") - .assertNormalExit(output -> output.shouldNotMatch(pattern)); - - // inspect the archive and make sure no anonymous class is in there - TestCommon.run("-XX:+UnlockDiagnosticVMOptions", - "-cp", appJar, "-Xlog:class+load=info", "-XX:+PrintSharedArchiveAndExit", - "-XX:+PrintSharedDictionary", "--add-modules", "java.corba", "Hello") - .assertNormalExit(output -> output.shouldNotMatch(class_pattern)); - } -} diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java index 453efd7237b..9e88df76728 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java @@ -32,7 +32,7 @@ * jdk.jartool/sun.tools.jar * jdk.internal.jvmstat/sun.jvmstat.monitor * @compile src/jdk/test/Main.java - * @compile src/com/sun/tools/javac/Main2.jasm + * @compile src/com/sun/tools/javac/MyMain.jasm * @compile src/sun/nio/cs/ext/MyClass.java * @compile src/sun/nio/cs/ext1/MyClass.java * @run main BootAppendTests @@ -52,7 +52,7 @@ public class BootAppendTests { private static final Path CLASSES_DIR = Paths.get("classes"); private static final String MAIN_CLASS = "jdk.test.Main"; - private static final String APP_MODULE_CLASS = "com/sun/tools/javac/Main2"; + private static final String APP_MODULE_CLASS = "com/sun/tools/javac/MyMain"; private static final String BOOT_APPEND_MODULE_CLASS = "sun/nio/cs/ext/MyClass"; private static final String BOOT_APPEND_CLASS = "sun/nio/cs/ext1/MyClass"; private static final String[] ARCHIVE_CLASSES = @@ -239,7 +239,7 @@ public class BootAppendTests { MAIN_CLASS, "Test #9", APP_MODULE_CLASS, "true", "BOOT") .assertSilentlyDisabledCDS(out -> { out.shouldHaveExitValue(0) - .shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar"); + .shouldMatch(".class.load. com.sun.tools.javac.MyMain source:.*bootAppend.jar"); }); } @@ -253,7 +253,7 @@ public class BootAppendTests { MAIN_CLASS, "Test #10", APP_MODULE_CLASS, "true", "BOOT") .assertSilentlyDisabledCDS(out -> { out.shouldHaveExitValue(0) - .shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar"); + .shouldMatch(".class.load. com.sun.tools.javac.MyMain source:.*bootAppend.jar"); }); } } diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/ClassPathTests.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/ClassPathTests.java index bd2bcada13f..5f2fd23fd7b 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/ClassPathTests.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/ClassPathTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,13 @@ * @requires vm.cds & !vm.graal.enabled * @library ../.. * @library /test/lib - * @modules java.base/jdk.internal.misc - * @modules jdk.jartool/sun.tools.jar + * @modules java.compiler + * java.base/jdk.internal.misc + * jdk.jartool/sun.tools.jar * @compile src/jdk/test/Main.java * @compile src/com/sun/tools/javac/Main.jasm - * @compile src/com/sun/tools/javac/Main2.jasm - * @compile src/javax/activation/UnsupportedDataTypeException2.jasm + * @compile src/com/sun/tools/javac/MyMain.jasm + * @compile ../../../SharedArchiveFile/javax/annotation/processing/FilerException.jasm * @run main ClassPathTests * @summary AppCDS tests for testing classpath/package conflicts */ @@ -73,8 +74,8 @@ public class ClassPathTests { // test classes to archive. These are both in UPGRADED_MODULES private static final String JIMAGE_CLASS = "com/sun/tools/javac/Main"; - private static final String APP_ARCHIVE_CLASS = "com/sun/tools/javac/Main2"; - private static final String PLATFORM_ARCHIVE_CLASS = "javax/activation/UnsupportedDataTypeException2"; + private static final String APP_ARCHIVE_CLASS = "com/sun/tools/javac/MyMain"; + private static final String PLATFORM_ARCHIVE_CLASS = "javax/annotation/processing/FilerException"; private static final String[] ARCHIVE_CLASSES = {APP_ARCHIVE_CLASS, PLATFORM_ARCHIVE_CLASS, JIMAGE_CLASS}; private static final int NUMBER_OF_TEST_CASES = 10; @@ -111,15 +112,17 @@ public class ClassPathTests { // dump the archive with altnernate jdk.comiler and jdk.activation classes in the class list OutputAnalyzer output1 = TestCommon.dump(appJar, TestCommon.list(ARCHIVE_CLASSES)); TestCommon.checkDump(output1); - // Only a class that belongs to a module which is not defined by default - // can be found. In this case the PLATFORM_ARCHIVE_CLASS belongs - // to the java.activation which is not defined by default; it is the only - // class can be found during dumping. + // The PLATFORM_ARCHIVE_CLASS belongs to the java.compiler + // module will be found from the module during dumping. + // The JIMAGE_CLASS will be found from the jdk.compiler module during + // dumping. + // The APP_ARCHIVE_CLASS, which belongs to a package within the + // jdk.compiler module, will not be found during dump time. for (String archiveClass : ARCHIVE_CLASSES) { - if (archiveClass.equals(PLATFORM_ARCHIVE_CLASS)) { - output1.shouldNotContain("Preload Warning: Cannot find " + archiveClass); - } else { + if (archiveClass.equals(APP_ARCHIVE_CLASS)) { output1.shouldContain("Preload Warning: Cannot find " + archiveClass); + } else { + output1.shouldNotContain("Preload Warning: Cannot find " + archiveClass); } } @@ -146,82 +149,86 @@ public class ClassPathTests { CDSTestUtils.runWithArchiveAndCheck(opts); } - // For tests #3 and #4, we need to "--add-modules java.activation" since the - // java.activation module won't be defined by default. - // #3: Archived classpath class in same package as jimage ext class. With AppCDS. - // Should fail to load. + // The class should be loaded from the module. public void testExtClassWithAppCDS() throws Exception { OutputAnalyzer output = TestCommon.exec( - appJar, "--add-modules", "java.activation", MAIN_CLASS, - "Test #3", PLATFORM_ARCHIVE_CLASS, "false"); // last 3 args passed to test + appJar, MAIN_CLASS, + "Test #3", PLATFORM_ARCHIVE_CLASS, "true", "EXT"); // last 4 args passed to test TestCommon.checkExec(output); } // #4: Archived classpath class in same package as jimage ext class. Without AppCDS. - // Should fail to load. + // The class should be loaded from the module. public void testExtClassWithoutAppCDS() throws Exception { CDSOptions opts = (new CDSOptions()) - .addPrefix("-cp", appJar, "--add-modules", "java.activation") + .addPrefix("-cp", appJar) .setArchiveName(testArchiveName) - .addSuffix(MAIN_CLASS, "Test #4", PLATFORM_ARCHIVE_CLASS, "false"); + .addSuffix(MAIN_CLASS, "Test #4", PLATFORM_ARCHIVE_CLASS, "true", "EXT"); CDSTestUtils.runWithArchiveAndCheck(opts); } // #5: Archived classpath class in same package as jimage app class. With AppCDS. - // Should load because --limit-modules is used. + // Should load with CDS disabled because --limit-modules is used. public void testAppClassWithLimitModsWithAppCDS() throws Exception { - OutputAnalyzer output = TestCommon.exec( - appJar, - "--limit-modules", "java.base", - MAIN_CLASS, - "Test #5", APP_ARCHIVE_CLASS, "true"); // last 3 args passed to test - TestCommon.checkExec(output); + TestCommon.run("-cp", appJar, + "--limit-modules", "java.base", + MAIN_CLASS, + "Test #5", APP_ARCHIVE_CLASS, "true") // last 3 args passed to test + .assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0); + }); } // #6: Archived classpath class in same package as jimage app class. Without AppCDS. - // Should load because --limit-modules is used. + // Should load with CDS disabled because --limit-modules is used. public void testAppClassWithLimitModsWithoutAppCDS() throws Exception { CDSOptions opts = (new CDSOptions()) .addPrefix("-cp", appJar, "--limit-modules", "java.base") .setArchiveName(testArchiveName) .addSuffix(MAIN_CLASS, "Test #6", APP_ARCHIVE_CLASS, "true"); - - CDSTestUtils.runWithArchiveAndCheck(opts); + CDSTestUtils.run(opts) + .assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0); + }); } // #7: Archived classpath class in same package as jimage ext class. With AppCDS. - // Should load because --limit-modules is used. + // Should load with CDS disabled because --limit-modules is used. public void testExtClassWithLimitModsWithAppCDS() throws Exception { - OutputAnalyzer output = TestCommon.exec( - appJar, - "--limit-modules", "java.base", - MAIN_CLASS, - "Test #7", PLATFORM_ARCHIVE_CLASS, "true"); // last 3 args passed to test - TestCommon.checkExec(output); + TestCommon.run("-cp", appJar, + "--limit-modules", "java.base", + MAIN_CLASS, + "Test #7", PLATFORM_ARCHIVE_CLASS, "true") // last 3 args passed to test + .assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0); + }); } // #8: Archived classpath class in same package as jimage ext class. Without AppCDS. - // Should load because --limit-modules is used. + // Should load with CDS disabled because --limit-modules is used. public void testExtClassWithLimitModsWithoutAppCDS() throws Exception { CDSOptions opts = (new CDSOptions()) .addPrefix("-cp", appJar, "--limit-modules", "java.base") .setArchiveName(testArchiveName) .addSuffix(MAIN_CLASS, "Test #8", PLATFORM_ARCHIVE_CLASS, "true"); - - CDSTestUtils.runWithArchiveAndCheck(opts); + CDSTestUtils.run(opts) + .assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0); + }); } // #9: Archived classpath class with same name as jimage app class. With AppCDS. - // Should load because --limit-modules is used. + // Should load with CDS disabled because --limit-modules is used. public void testReplacingJImageClassWithAppCDS() throws Exception { - OutputAnalyzer output = TestCommon.exec( - appJar, - "--limit-modules", "java.base", "-XX:+TraceClassLoading", - MAIN_CLASS, - "Test #9", JIMAGE_CLASS, "true"); // last 3 args passed to test - TestCommon.checkExec(output); + TestCommon.run("-cp", appJar, + "--limit-modules", "java.base", + MAIN_CLASS, + "Test #9", JIMAGE_CLASS, "true") // last 3 args passed to test + .assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0); + }); } // #10: Archived classpath class with same name as jimage app class. Without AppCDS. @@ -233,8 +240,9 @@ public class ClassPathTests { .addPrefix("-cp", appJar, "--limit-modules", "java.base") .setArchiveName(testArchiveName) .addSuffix(MAIN_CLASS, "Test #10", JIMAGE_CLASS, "true"); - - CDSTestUtils.runWithArchiveAndCheck(opts); + CDSTestUtils.run(opts) + .assertSilentlyDisabledCDS(out -> { + out.shouldHaveExitValue(0); + }); } - } diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java index a5fec614fe5..dfa0ee3babf 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java @@ -27,11 +27,11 @@ * @summary Ensure that classes found in jimage takes precedence over classes found in -Xbootclasspath/a. * @requires vm.cds * @library /test/lib /test/hotspot/jtreg/runtime/appcds - * @modules java.activation + * @modules java.compiler * jdk.jartool/sun.tools.jar * @compile ../../test-classes/DummyClassHelper.java * @compile ../../test-classes/java/net/HttpCookie.jasm - * @compile ../../test-classes/javax/activation/MimeType.jasm + * @compile ../../../SharedArchiveFile/javax/annotation/processing/FilerException.jasm * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run main DummyClassesInBootClassPath @@ -57,21 +57,20 @@ public class DummyClassesInBootClassPath { public static void main(String[] args) throws Exception { String classNames[] = { "java/net/HttpCookie", - "javax/activation/MimeType"}; + "javax/annotation/processing/FilerException"}; JarBuilder.build("dummyClasses", classNames[0], classNames[1]); String appJar = TestCommon.getTestJar("dummyClasses.jar"); OutputAnalyzer dumpOutput = TestCommon.dump( - appJar, classNames, "-Xbootclasspath/a:" + appJar, - "--add-modules", "java.activation"); + appJar, classNames, "-Xbootclasspath/a:" + appJar); List argsList = new ArrayList(); for (int i = 0; i < classNames.length; i++) { argsList.add(classNames[i].replace('/', '.')); } String[] arguments = new String[argsList.size()]; arguments = argsList.toArray(arguments); - Testcommon.run( - "--add-modules", "java.activation", "-Xbootclasspath/a:" + appJar, + TestCommon.run( + "-Xbootclasspath/a:" + appJar, "DummyClassHelper", arguments[0], arguments[1]) .assertNormalExit(output -> checkOutput(output, classNames)); @@ -80,14 +79,14 @@ public class DummyClassesInBootClassPath { String bootClassPath = "-Xbootclasspath/a:" + appJar + File.pathSeparator + whiteBoxJar; dumpOutput = TestCommon.dump( - appJar, classNames, bootClassPath, "--add-modules", "java.activation"); + appJar, classNames, bootClassPath); argsList.add("testWithWhiteBox"); arguments = new String[argsList.size()]; arguments = argsList.toArray(arguments); String[] opts = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "--add-modules", "java.activation", bootClassPath, "-Xlog:class+path=trace", + bootClassPath, "-Xlog:class+path=trace", "DummyClassHelper", arguments[0], arguments[1], arguments[2]}; - Testcommon.run(opts) + TestCommon.run(opts) .assertNormalExit(output -> checkOutput(output, classNames)); } } diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/Main2.jasm b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/MyMain.jasm similarity index 93% rename from test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/Main2.jasm rename to test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/MyMain.jasm index 3d0f43256bf..b35231d17e9 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/Main2.jasm +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/com/sun/tools/javac/MyMain.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ package com/sun/tools/javac; -public class Main2 +public class MyMain version 51:0 { diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/javax/activation/UnsupportedDataTypeException2.jasm b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/javax/activation/UnsupportedDataTypeException2.jasm deleted file mode 100644 index 3a30e511397..00000000000 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/javax/activation/UnsupportedDataTypeException2.jasm +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 javax/activation; - -public class UnsupportedDataTypeException2 - version 51:0 -{ - -public Method "":"()V" - stack 1 locals 1 -{ - aload_0; - invokespecial Method java/lang/Object."":"()V"; - return; -} - -public Method toString:"()Ljava/lang/String;" - stack 1 locals 1 -{ - ldc String "hi"; - areturn; -} - -} // end class UnsupportedDataTypeException2 diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/jdk/test/Main.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/jdk/test/Main.java index 752fd9b7baf..76ca5700fbe 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/jdk/test/Main.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/src/jdk/test/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,10 +96,12 @@ public class Main { } // Make sure we got the right version of the class. toString() of an instance // of the overridden version of the class should return "hi". - String s = clazz.newInstance().toString(); - if (!s.equals("hi")) { - throw new RuntimeException(testName + " FAILED: toString() returned \"" + s - + "\" instead of \"hi\"" ); + if (actualLoader == SYS_LOADER) { + String s = clazz.newInstance().toString(); + if (!s.equals("hi")) { + throw new RuntimeException(testName + " FAILED: toString() returned \"" + s + + "\" instead of \"hi\"" ); + } } System.out.println(testName + " PASSED: class loaded as expected."); } else { diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/OverrideTests.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/OverrideTests.java index f6056fe1775..3a8707e21ed 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/OverrideTests.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/OverrideTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ public class OverrideTests { private static final Path MODS_DIR = Paths.get("mods"); // the module that is upgraded - private static final String[] UPGRADED_MODULES = {"jdk.compiler", "java.activation"}; + private static final String[] UPGRADED_MODULES = {"jdk.compiler", "java.net.http"}; private static final Path[] UPGRADEDMODS_DIR = {Paths.get("upgradedmod1"), Paths.get("upgradedmod2")}; // the test module @@ -76,7 +76,7 @@ public class OverrideTests { // test classes to archive. These are both in UPGRADED_MODULES private static final String APP_ARCHIVE_CLASS = "com/sun/tools/javac/Main"; - private static final String PLATFORM_ARCHIVE_CLASS = "javax/activation/UnsupportedDataTypeException"; + private static final String PLATFORM_ARCHIVE_CLASS = "java/net/http/HttpTimeoutException"; private static final String[] ARCHIVE_CLASSES = {APP_ARCHIVE_CLASS, PLATFORM_ARCHIVE_CLASS}; private static String testArchiveName; @@ -94,10 +94,10 @@ public class OverrideTests { int i = 0; for (String upgradedMod : UPGRADED_MODULES) { compiled = CompilerUtils.compile( - SRC_DIR.resolve(upgradedMod), - UPGRADEDMODS_DIR[i].resolve(upgradedMod) + SRC_DIR.resolve(UPGRADED_MODULES[i]), + UPGRADEDMODS_DIR[i].resolve(UPGRADED_MODULES[i]) ); - Asserts.assertTrue(compiled, upgradedMod + " did not compile"); + Asserts.assertTrue(compiled, UPGRADED_MODULES[i] + " did not compile"); i++; } @@ -110,22 +110,12 @@ public class OverrideTests { ); Asserts.assertTrue(compiled, TEST_MODULE + " did not compile"); - // the java.activation module is not defined by default; --add-modules is required. - // dumping without "--add-modules java.activation" - // the class in the javax.activation package cannot be found - OutputAnalyzer output1 = TestCommon.dump(null /* appJar*/, TestCommon.list(ARCHIVE_CLASSES)); - TestCommon.checkDump(output1); - output1.shouldContain( - "Preload Warning: Cannot find javax/activation/UnsupportedDataTypeException"); - - // dump the archive with jdk.comiler and java.activation classes in the class list - // with "--add-modules java.activation" - output1 = TestCommon.dump(null /* appJar*/, TestCommon.list(ARCHIVE_CLASSES), - "--add-modules", "java.activation"); - TestCommon.checkDump(output1); + // dump the archive with jdk.compiler and java.net.http classes in the class list + OutputAnalyzer output = TestCommon.dump(null /* appJar*/, TestCommon.list(ARCHIVE_CLASSES)); + TestCommon.checkDump(output); // Make sure all the classes where successfully archived. for (String archiveClass : ARCHIVE_CLASSES) { - output1.shouldNotContain("Preload Warning: Cannot find " + archiveClass); + output.shouldNotContain("Preload Warning: Cannot find " + archiveClass); } testArchiveName = TestCommon.getCurrentArchiveName(); @@ -147,11 +137,11 @@ public class OverrideTests { /** * PLATFORM Class Overriding Tests * - * Archive PLATFORM class javax.activation.UnsupportedDataTypeException from module jdk.activation. - * -At run time, upgrade module jdk.activation using --upgrade-module-path. - * Class.forname(UnsupportedDataTypeException) MUST NOT load the archived UnsupportedDataTypeException. - * -At run time, module jdk.activation also exists in --module-path. - * Class.forname(UnsupportedDataTypeException) MUST load the archived UnsupportedDataTypeException. + * Archive PLATFORM class java.net.http.HttpTimeoutException from module java.net.http. + * -At run time, upgrade module java.net.http using --upgrade-module-path. + * Class.forname(HttpTimeoutException) MUST NOT load the archived HttpTimeoutException. + * -At run time, module java.net.http also exists in --module-path. + * Class.forname(HttpTimeoutException) MUST load the archived HttpTimeoutException. */ public void testPlatformClassOverriding() throws Exception { testClassOverriding(PLATFORM_ARCHIVE_CLASS, "platform"); @@ -173,25 +163,16 @@ public class OverrideTests { prefix[0] = "-cp"; prefix[1] = "\"\""; prefix[2] = "--add-modules"; - prefix[3] = "java.activation"; + prefix[3] = "java.net.http"; // Run the test with --upgrade-module-path set to alternate location of archiveClass // The alternate version of archiveClass SHOULD be found. - output = TestCommon.execModule( - prefix, - UPGRADEDMODS_DIR[upgradeModIdx].toString(), - MODS_DIR.toString(), - mid, - archiveClass, loaderName, "true"); // last 3 args passed to test - if (isAppLoader) { - try { - output.shouldContain(expectedException); - } catch (Exception e) { - TestCommon.checkCommonExecExceptions(output, e); - } - } else { - TestCommon.checkExec(output); - } + TestCommon.runWithModules(prefix, + UPGRADEDMODS_DIR[upgradeModIdx].toString(), + MODS_DIR.toString(), + mid, + archiveClass, loaderName, "true") // last 3 args passed to test + .ifNoMappingFailure(out -> out.shouldContain(expectedException)); // Now run this same test again, but this time without AppCDS. Behavior should be the same. CDSOptions opts = (new CDSOptions()) @@ -203,26 +184,21 @@ public class OverrideTests { output = CDSTestUtils.runWithArchive(opts); - if (isAppLoader) { - try { - output.shouldContain(expectedException); - } catch (Exception e) { - TestCommon.checkCommonExecExceptions(output, e); - } - } else { - if (!CDSTestUtils.isUnableToMap(output)) - output.shouldHaveExitValue(0); + try { + output.shouldContain(expectedException); + } catch (Exception e) { + TestCommon.checkCommonExecExceptions(output, e); } // Run the test with -p set to alternate location of archiveClass. // The alternate version of archiveClass SHOULD NOT be found. - output = TestCommon.execModule( + TestCommon.runWithModules( prefix, null, UPGRADEDMODS_DIR[upgradeModIdx].toString() + java.io.File.pathSeparator + MODS_DIR.toString(), mid, - archiveClass, loaderName, "false"); // last 3 args passed to test - TestCommon.checkExec(output); + archiveClass, loaderName, "false") // last 3 args passed to test + .assertNormalExit(); // Now run this same test again, but this time without AppCDS. Behavior should be the same. opts = (new CDSOptions()) diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.activation/javax/activation/UnsupportedDataTypeException.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.net.http/java/net/http/HttpTimeoutException.java similarity index 80% rename from test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.activation/javax/activation/UnsupportedDataTypeException.java rename to test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.net.http/java/net/http/HttpTimeoutException.java index 3016bb41a10..a1c5356e2fb 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.activation/javax/activation/UnsupportedDataTypeException.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.net.http/java/net/http/HttpTimeoutException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,14 +22,9 @@ * */ -package javax.activation; - -import java.io.IOException; - -public class UnsupportedDataTypeException extends IOException { - public UnsupportedDataTypeException() { - } +package java.net.http; +public class HttpTimeoutException { public String toString() { return "hi"; } diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.activation/module-info.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.net.http/module-info.java similarity index 95% rename from test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.activation/module-info.java rename to test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.net.http/module-info.java index 23c707a46f7..52e094e3f5f 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.activation/module-info.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/java.net.http/module-info.java @@ -22,7 +22,7 @@ * */ -module java.activation { - exports javax.activation; +module java.net.http { + exports java.net.http; } diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/jdk/test/Main.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/jdk/test/Main.java index e752f4d3da5..b2098007616 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/jdk/test/Main.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/jdk/test/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,11 +73,15 @@ public class Main { Class clazz = Class.forName(className, true, loader); // Make sure we got the expected defining ClassLoader testLoader(clazz, loader); - // Create an instance and see what toString() returns - String s = clazz.newInstance().toString(); + + String s = null; + if (shouldOverride) { + // Create an instance and see what toString() returns + clazz.newInstance().toString(); + } // The overridden version of the class should return "hi". Make sure // it does only if we are expecting to have loaded the overridden version. - assertTrue(s.equals("hi") == shouldOverride); + assertTrue("hi".equals(s) == shouldOverride); } /** diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/module-info.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/module-info.java index 8ca8942555b..772edc1e0e0 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/module-info.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/overridetests/src/test/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,5 +24,5 @@ module test { requires jdk.compiler; - requires java.activation; + requires java.compiler; } diff --git a/test/hotspot/jtreg/runtime/appcds/test-classes/HelloExt.java b/test/hotspot/jtreg/runtime/appcds/test-classes/HelloExt.java index bd11763271a..6a09f0fdcd8 100644 --- a/test/hotspot/jtreg/runtime/appcds/test-classes/HelloExt.java +++ b/test/hotspot/jtreg/runtime/appcds/test-classes/HelloExt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import sun.hotspot.WhiteBox; public class HelloExt { public static void main(String[] args) throws Throwable { - String className = "org.omg.CORBA.ORB"; + String className = "javax.annotation.processing.FilerException"; Class cls = Class.forName(className); ClassLoader loader = cls.getClassLoader(); diff --git a/test/hotspot/jtreg/runtime/appcds/test-classes/javax/activation/MimeType.jasm b/test/hotspot/jtreg/runtime/appcds/test-classes/javax/activation/MimeType.jasm deleted file mode 100644 index 1436fe9b4ab..00000000000 --- a/test/hotspot/jtreg/runtime/appcds/test-classes/javax/activation/MimeType.jasm +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 javax/activation; - -public class MimeType - version 51:0 -{ - -public Method thisClassIsDummy:"()V" - stack 0 locals 0 -{ - return; -} - -} // end class MimeType diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index d16944eb8b7..dc21b9fc3d2 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -366,6 +366,10 @@ public class CDSTestUtils { return new Result(opts, runWithArchive(opts)); } + public static Result run(CDSOptions opts) throws Exception { + return new Result(opts, runWithArchive(opts)); + } + // Execute JVM with CDS archive, specify command line args suffix public static OutputAnalyzer runWithArchive(String... cliPrefix) throws Exception { From 15ef60b3506d7d464c599367cbeea8bb374ab7a6 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 25 Apr 2018 22:12:06 -0700 Subject: [PATCH 050/102] 8200478: For boxing conversion javac uses Long.valueOf which does not guarantee caching according to its javadoc Reviewed-by: bpb --- src/java.base/share/classes/java/lang/Long.java | 6 ++---- test/langtools/tools/javac/boxing/BoxingCaching.java | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 6a43e1b5d8e..956dd6f5139 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -1164,10 +1164,8 @@ public final class Long extends Number implements Comparable { * significantly better space and time performance by caching * frequently requested values. * - * Note that unlike the {@linkplain Integer#valueOf(int) - * corresponding method} in the {@code Integer} class, this method - * is not required to cache values within a particular - * range. + * This method will always cache values in the range -128 to 127, + * inclusive, and may cache other values outside of this range. * * @param l a long value. * @return a {@code Long} instance representing {@code l}. diff --git a/test/langtools/tools/javac/boxing/BoxingCaching.java b/test/langtools/tools/javac/boxing/BoxingCaching.java index 29eb9fca95a..2d7acb817f0 100644 --- a/test/langtools/tools/javac/boxing/BoxingCaching.java +++ b/test/langtools/tools/javac/boxing/BoxingCaching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4990346 + * @bug 4990346 8200478 * @summary Verify autoboxed values are cached as required. * @author Joseph D. Darcy */ @@ -155,7 +155,7 @@ public class BoxingCaching { Long L = (long)(i-128); if (L != results[i]) { cached = false; - System.err.println("Integer value " + L + + System.err.println("Long value " + L + " is not cached appropriately."); } } From ccc74fdd600d4da4babc47bc72910e8b2c75dde8 Mon Sep 17 00:00:00 2001 From: Jini George Date: Thu, 26 Apr 2018 12:25:36 +0530 Subject: [PATCH 051/102] 8174994: SA: clhsdb printmdo throws WrongTypeException when attached to a process with CDS Read in the md region of the CDS archive in SA and map the vtable addresses to the corresponding metadata type. Reviewed-by: iklam, coleenp, ysuenaga, dholmes --- src/hotspot/share/memory/filemap.hpp | 1 + src/hotspot/share/runtime/vmStructs.cpp | 17 +- .../linux/native/libsaproc/ps_core.c | 50 +++- .../macosx/native/libsaproc/ps_core.c | 60 +++-- .../sun/jvm/hotspot/memory/FileMapInfo.java | 148 +++++++++++ .../classes/sun/jvm/hotspot/runtime/VM.java | 13 +- .../types/basic/BasicTypeDataBase.java | 12 +- .../solaris/native/libsaproc/saproc.cpp | 65 +++-- .../serviceability/sa/ClhsdbCDSCore.java | 247 ++++++++++++++++++ .../sa/ClhsdbCDSJstackPrintAll.java | 112 ++++++++ .../serviceability/sa/ClhsdbLauncher.java | 50 ++++ 11 files changed, 719 insertions(+), 56 deletions(-) create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java create mode 100644 test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java create mode 100644 test/hotspot/jtreg/serviceability/sa/ClhsdbCDSJstackPrintAll.java diff --git a/src/hotspot/share/memory/filemap.hpp b/src/hotspot/share/memory/filemap.hpp index 1a6a4ebd967..55914e92562 100644 --- a/src/hotspot/share/memory/filemap.hpp +++ b/src/hotspot/share/memory/filemap.hpp @@ -75,6 +75,7 @@ public: class FileMapInfo : public CHeapObj { private: friend class ManifestStream; + friend class VMStructs; enum { _invalid_version = -1, _current_version = 3 diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 9e5f1294b2c..fd473a58268 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -56,6 +56,7 @@ #include "memory/referenceType.hpp" #include "memory/universe.hpp" #include "memory/virtualspace.hpp" +#include "memory/filemap.hpp" #include "oops/array.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" @@ -1120,6 +1121,16 @@ typedef PaddedEnd PaddedObjectMonitor; static_field(java_lang_Class, _oop_size_offset, int) \ static_field(java_lang_Class, _static_oop_field_count_offset, int) \ \ + /********************************************/ \ + /* FileMapInfo fields (CDS archive related) */ \ + /********************************************/ \ + \ + nonstatic_field(FileMapInfo, _header, FileMapInfo::FileMapHeader*) \ + static_field(FileMapInfo, _current_info, FileMapInfo*) \ + nonstatic_field(FileMapInfo::FileMapHeader, _space[0], FileMapInfo::FileMapHeader::space_info)\ + nonstatic_field(FileMapInfo::FileMapHeader::space_info, _addr._base, char*) \ + nonstatic_field(FileMapInfo::FileMapHeader::space_info, _used, size_t) \ + \ /******************/ \ /* VMError fields */ \ /******************/ \ @@ -1444,7 +1455,7 @@ typedef PaddedEnd PaddedObjectMonitor; declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ - declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ + declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -2000,6 +2011,10 @@ typedef PaddedEnd PaddedObjectMonitor; declare_toplevel_type(vframeArrayElement) \ declare_toplevel_type(Annotations*) \ declare_type(OopMapValue, StackObj) \ + declare_type(FileMapInfo, CHeapObj) \ + declare_type(FileMapInfo::FileMapHeaderBase, CHeapObj) \ + declare_type(FileMapInfo::FileMapHeader, FileMapInfo::FileMapHeaderBase)\ + declare_toplevel_type(FileMapInfo::FileMapHeader::space_info) \ \ /************/ \ /* GC types */ \ diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c index cf573d01ed2..93262477a3d 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c @@ -212,29 +212,51 @@ static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { // mapped. This structure gets written to a file. It is not a class, // so that the compilers don't add any compiler-private data to it. -#define NUM_SHARED_MAPS 4 +#define NUM_SHARED_MAPS 9 // Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 1 +#define CURRENT_ARCHIVE_VERSION 3 + +typedef unsigned char* address; +typedef uintptr_t uintx; +typedef intptr_t intx; struct FileMapHeader { - int _magic; // identify file type. - int _version; // (from enum, above.) - size_t _alignment; // how shared archive should be aligned + int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base + int _narrow_oop_shift; // compressed oop encoding shift + bool _compact_strings; // value of CompactStrings + uintx _max_heap_size; // java max heap size during dumping + int _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). + struct space_info { - int _file_offset; // sizeof(this) rounded to vm page size - char* _base; // copy-on-write base address - size_t _capacity; // for validity checking - size_t _used; // for setting space top on read - + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + intx _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with // the C type matching the C++ bool type on any given platform. // We assume the corresponding C type is char but licensees // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - + char _read_only; // read only space? + char _allow_exec; // executable code in space? } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. @@ -381,7 +403,7 @@ static bool init_classsharing_workaround(struct ps_prochandle* ph) { // add read-only maps from classes.jsa to the list of maps for (m = 0; m < NUM_SHARED_MAPS; m++) { if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; + base = (uintptr_t) header._space[m]._addr._base; // no need to worry about the fractional pages at-the-end. // possible fractional pages are handled by core_read_data. add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c index b4dacf6e6ac..f5798e38ca8 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,29 +213,52 @@ static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { // mapped. This structure gets written to a file. It is not a class, // so that the compilers don't add any compiler-private data to it. -#define NUM_SHARED_MAPS 4 +#define NUM_SHARED_MAPS 9 // Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 1 +#define CURRENT_ARCHIVE_VERSION 3 + +typedef unsigned char* address; +typedef uintptr_t uintx; +typedef intptr_t intx; + struct FileMapHeader { - int _magic; // identify file type. - int _version; // (from enum, above.) - size_t _alignment; // how shared archive should be aligned + int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base + int _narrow_oop_shift; // compressed oop encoding shift + bool _compact_strings; // value of CompactStrings + uintx _max_heap_size; // java max heap size during dumping + int _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). + struct space_info { - int _file_offset; // sizeof(this) rounded to vm page size - char* _base; // copy-on-write base address - size_t _capacity; // for validity checking - size_t _used; // for setting space top on read - + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + intx _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with // the C type matching the C++ bool type on any given platform. // We assume the corresponding C type is char but licensees // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - + char _read_only; // read only space? + char _allow_exec; // executable code in space? } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. @@ -282,15 +305,14 @@ static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, siz return true; } +// mangled name of Arguments::SharedArchivePath +#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" + #ifdef __APPLE__ #define USE_SHARED_SPACES_SYM "_UseSharedSpaces" -// mangled name of Arguments::SharedArchivePath -#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" #define LIBJVM_NAME "/libjvm.dylib" #else #define USE_SHARED_SPACES_SYM "UseSharedSpaces" -// mangled name of Arguments::SharedArchivePath -#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" #define LIBJVM_NAME "/libjvm.so" #endif // __APPLE_ @@ -387,7 +409,7 @@ static bool init_classsharing_workaround(struct ps_prochandle* ph) { // add read-only maps from classes.jsa to the list of maps for (m = 0; m < NUM_SHARED_MAPS; m++) { if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; + base = (uintptr_t) header._space[m]._addr._base; // no need to worry about the fractional pages at-the-end. // possible fractional pages are handled by core_read_data. add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java new file mode 100644 index 00000000000..27242466323 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.memory; + +import java.util.*; +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObject; +import sun.jvm.hotspot.runtime.VMObjectFactory; +import sun.jvm.hotspot.types.*; + +public class FileMapInfo { + private static FileMapHeader header; + private static Address headerValue; + + // Fields for class FileMapHeader + private static Address mdSpaceValue; + private static Address mdRegionBaseAddress; + private static Address mdRegionEndAddress; + + // HashMap created by mapping the vTable addresses in the md region with + // the corresponding metadata type. + private static Map vTableTypeMap; + + private static Type metadataTypeArray[]; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + // FileMapInfo + Type type = db.lookupType("FileMapInfo"); + AddressField currentInfoField = type.getAddressField("_current_info"); + long headerFieldOffset = type.getField("_header").getOffset(); + Address headerAddress = currentInfoField.getValue().addOffsetTo(headerFieldOffset); + headerValue = headerAddress.getAddressAt(0); + + // FileMapHeader + type = db.lookupType("FileMapInfo::FileMapHeader"); + AddressField spaceField = type.getAddressField("_space[0]"); + Address spaceValue = headerValue.addOffsetTo(type.getField("_space[0]").getOffset()); + mdSpaceValue = spaceValue.addOffsetTo(3 * spaceField.getSize()); + + // SpaceInfo + type = db.lookupType("FileMapInfo::FileMapHeader::space_info"); + long mdRegionBaseAddressOffset = type.getField("_addr._base").getOffset(); + mdRegionBaseAddress = (mdSpaceValue.addOffsetTo(mdRegionBaseAddressOffset)).getAddressAt(0); + long mdRegionSizeOffset = type.getField("_used").getOffset(); + long mdRegionSize = (mdSpaceValue.addOffsetTo(mdRegionSizeOffset)).getAddressAt(0).asLongValue(); + mdRegionEndAddress = mdRegionBaseAddress.addOffsetTo(mdRegionSize); + + populateMetadataTypeArray(db); + } + + private static void populateMetadataTypeArray(TypeDataBase db) { + metadataTypeArray = new Type[8]; + + metadataTypeArray[0] = db.lookupType("ConstantPool"); + metadataTypeArray[1] = db.lookupType("InstanceKlass"); + metadataTypeArray[2] = db.lookupType("InstanceClassLoaderKlass"); + metadataTypeArray[3] = db.lookupType("InstanceMirrorKlass"); + metadataTypeArray[4] = db.lookupType("InstanceRefKlass"); + metadataTypeArray[5] = db.lookupType("Method"); + metadataTypeArray[6] = db.lookupType("ObjArrayKlass"); + metadataTypeArray[7] = db.lookupType("TypeArrayKlass"); + } + + public FileMapHeader getHeader() { + if (header == null) { + header = (FileMapHeader) VMObjectFactory.newObject(FileMapInfo.FileMapHeader.class, headerValue); + } + return header; + } + + public boolean inCopiedVtableSpace(Address vptrAddress) { + FileMapHeader fmHeader = getHeader(); + return fmHeader.inCopiedVtableSpace(vptrAddress); + } + + public Type getTypeForVptrAddress(Address vptrAddress) { + if (vTableTypeMap == null) { + getHeader().createVtableTypeMapping(); + } + return vTableTypeMap.get(vptrAddress); + } + + + //------------------------------------------------------------------------------------------ + + public static class FileMapHeader extends VMObject { + + public FileMapHeader(Address addr) { + super(addr); + } + + public boolean inCopiedVtableSpace(Address vptrAddress) { + if (vptrAddress.greaterThan(mdRegionBaseAddress) && + vptrAddress.lessThanOrEqual(mdRegionEndAddress)) { + return true; + } + return false; + } + + public void createVtableTypeMapping() { + vTableTypeMap = new HashMap(); + long metadataVTableSize = 0; + long addressSize = VM.getVM().getAddressSize(); + + Address copiedVtableAddress = mdRegionBaseAddress; + for (int i=0; i < metadataTypeArray.length; i++) { + // The first entry denotes the vtable size. + metadataVTableSize = copiedVtableAddress.getAddressAt(0).asLongValue(); + vTableTypeMap.put(copiedVtableAddress.addOffsetTo(addressSize), metadataTypeArray[i]); + + // The '+ 1' below is to skip the entry containing the size of this metadata's vtable. + copiedVtableAddress = + copiedVtableAddress.addOffsetTo((metadataVTableSize + 1) * addressSize); + } + } + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index fe180f189e2..465937dc822 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ public class VM { private JNIHandles handles; private Interpreter interpreter; private StubRoutines stubRoutines; + private FileMapInfo fileMapInfo; private Bytes bytes; /** Flag indicating if JVMTI support is included in the build */ @@ -717,6 +718,16 @@ public class VM { return vmregImpl; } + public FileMapInfo getFileMapInfo() { + if (!isSharingEnabled()) { + return null; + } + if (fileMapInfo == null) { + fileMapInfo = new FileMapInfo(); + } + return fileMapInfo; + } + public Bytes getBytes() { if (bytes == null) { bytes = new Bytes(debugger.getMachineDescription()); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java index 910e15e0f37..719075dfa18 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import sun.jvm.hotspot.debugger.MachineDescription; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.memory.FileMapInfo; /**

This is a basic implementation of the TypeDataBase interface. It allows an external type database builder to add types to be @@ -294,6 +295,15 @@ public class BasicTypeDataBase implements TypeDataBase { // the locations searched. Address loc1 = addr.getAddressAt(0); + + if (VM.getVM().isSharingEnabled()) { + // Check if the value falls in the _md_region + FileMapInfo cdsFileMapInfo = VM.getVM().getFileMapInfo(); + if (cdsFileMapInfo.inCopiedVtableSpace(loc1)) { + return cdsFileMapInfo.getTypeForVptrAddress(loc1); + } + } + Address loc2 = null; Address loc3 = null; long offset2 = baseType.getSize(); diff --git a/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp b/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp index dd5c0e332d5..27d00d63924 100644 --- a/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp +++ b/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,29 +496,54 @@ wrapper_fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc, // mapped. This structure gets written to a file. It is not a class, so // that the compilers don't add any compiler-private data to it. -const int NUM_SHARED_MAPS = 4; +const int NUM_SHARED_MAPS = 9; // Refer to FileMapInfo::_current_version in filemap.hpp -const int CURRENT_ARCHIVE_VERSION = 1; +const int CURRENT_ARCHIVE_VERSION = 3; + +typedef unsigned char* address; +typedef uintptr_t uintx; +typedef intptr_t intx; struct FileMapHeader { - int _magic; // identify file type. - int _version; // (from enum, above.) - size_t _alignment; // how shared archive should be aligned + int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base + int _narrow_oop_shift; // compressed oop encoding shift + bool _compact_strings; // value of CompactStrings + uintx _max_heap_size; // java max heap size during dumping + int _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). - struct space_info { - int _file_offset; // sizeof(this) rounded to vm page size - char* _base; // copy-on-write base address - size_t _capacity; // for validity checking - size_t _used; // for setting space top on read + struct space_info { + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + intx _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read + // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with + // the C type matching the C++ bool type on any given platform. + // We assume the corresponding C type is char but licensees + // may need to adjust the type of these fields. + char _read_only; // read only space? + char _allow_exec; // executable code in space? + } _space[NUM_SHARED_MAPS]; - bool _read_only; // read only space? - bool _allow_exec; // executable code in space? - - } _space[NUM_SHARED_MAPS]; - - // Ignore the rest of the FileMapHeader. We don't need those fields here. +// Ignore the rest of the FileMapHeader. We don't need those fields here. }; static bool @@ -677,7 +702,7 @@ init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name if (_libsaproc_debug) { for (int m = 0; m < NUM_SHARED_MAPS; m++) { print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n", - pheader->_space[m]._file_offset, pheader->_space[m]._base, + pheader->_space[m]._file_offset, pheader->_space[m]._addr._base, pheader->_space[m]._used, pheader->_space[m]._read_only); } } @@ -1058,7 +1083,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLoca print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address); struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); - // walk through the shared mappings -- we just have 4 of them. + // walk through the shared mappings -- we just have 9 of them. // so, linear walking is okay. for (int m = 0; m < NUM_SHARED_MAPS; m++) { @@ -1066,7 +1091,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLoca // and hence will be read by libproc. Besides, the file copy may be // stale because the process might have modified those pages. if (pheader->_space[m]._read_only) { - jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base; + jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._addr._base; size_t usedSize = pheader->_space[m]._used; if (address >= baseAddress && address < (baseAddress + usedSize)) { // the given address falls in this shared heap area diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java new file mode 100644 index 00000000000..d903c579d6c --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174994 + * @summary Test the clhsdb commands 'printmdo', 'printall' on a CDS enabled corefile. + * @requires vm.cds + * @requires os.family != "windows" + * @requires vm.flavor == "server" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run main/othervm/timeout=2400 -Xmx1g ClhsdbCDSCore + */ + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.HashMap; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.CDSOptions; +import java.io.IOException; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.Asserts; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import jdk.internal.misc.Unsafe; +import java.util.Scanner; + +class CrashApp { + public static void main(String[] args) { + Unsafe.getUnsafe().putInt(0L, 0); + } +} + +public class ClhsdbCDSCore { + + private static final String TEST_CDS_CORE_FILE_NAME = "cds_core_file"; + private static final String LOCATIONS_STRING = "location: "; + private static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && "; + private static final String SHARED_ARCHIVE_NAME = "ArchiveForClhsdbCDSCore.jsa"; + private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern"; + + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbCDSCore test"); + cleanup(); + + try { + CDSOptions opts = (new CDSOptions()).setArchiveName(SHARED_ARCHIVE_NAME); + CDSTestUtils.createArchiveAndCheck(opts); + + String[] jArgs = { + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + SHARED_ARCHIVE_NAME, + "-XX:+CreateCoredumpOnCrash", + "-Xshare:auto", + "-XX:+ProfileInterpreter", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + CrashApp.class.getName() + }; + + OutputAnalyzer crashOut; + try { + List options = new ArrayList<>(); + options.addAll(Arrays.asList(jArgs)); + crashOut = + ProcessTools.executeProcess(getTestJavaCommandlineWithPrefix( + RUN_SHELL_NO_LIMIT, options.toArray(new String[0]))); + } catch (Throwable t) { + throw new Error("Can't execute the java cds process.", t); + } + + System.out.println(crashOut.getOutput()); + String crashOutputString = crashOut.getOutput(); + String coreFileLocation = getCoreFileLocation(crashOutputString); + if (coreFileLocation == null) { + if (Platform.isOSX()) { + File coresDir = new File("/cores"); + if (!coresDir.isDirectory() || !coresDir.canWrite()) { + throw new Error("cores is not a directory or does not have write permissions"); + } + } else if (Platform.isLinux()) { + // Check if a crash report tool is installed. + File corePatternFile = new File(CORE_PATTERN_FILE_NAME); + Scanner scanner = new Scanner(corePatternFile); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.trim(); + System.out.println(line); + if (line.startsWith("|")) { + System.out.println( + "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" + + "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" + + "to enable core generation. Skipping this test."); + cleanup(); + return; + } + } + } + throw new Error("Couldn't find core file location in: '" + crashOutputString + "'"); + } + try { + Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size"); + Files.move(Paths.get(coreFileLocation), Paths.get(TEST_CDS_CORE_FILE_NAME)); + } catch (IOException ioe) { + throw new Error("Can't move core file: " + ioe, ioe); + } + + ClhsdbLauncher test = new ClhsdbLauncher(); + + // Ensure that UseSharedSpaces is turned on. + List cmds = List.of("flags UseSharedSpaces"); + + String useSharedSpacesOutput = test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, + null, null); + + if (useSharedSpacesOutput == null) { + // Output could be null due to attach permission issues. + System.out.println("Could not determine the UseSharedSpaces value - test skipped."); + cleanup(); + return; + } + + if (!useSharedSpacesOutput.contains("true")) { + // CDS archive is not mapped. Skip the rest of the test. + System.out.println("The CDS archive is not mapped - test skipped."); + cleanup(); + return; + } + + cmds = List.of("printmdo -a", "printall"); + + Map> expStrMap = new HashMap<>(); + Map> unExpStrMap = new HashMap<>(); + expStrMap.put("printmdo -a", List.of( + "CounterData", + "BranchData")); + unExpStrMap.put("printmdo -a", List.of( + "No suitable match for type of address")); + expStrMap.put("printall", List.of( + "aload_0", + "Constant Pool of", + "public static void main(java.lang.String[])", + "Bytecode", + "invokevirtual", + "checkcast", + "Exception Table", + "invokedynamic")); + unExpStrMap.put("printall", List.of( + "sun.jvm.hotspot.types.WrongTypeException", + "No suitable match for type of address")); + test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, expStrMap, unExpStrMap); + } catch (Exception ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } + cleanup(); + System.out.println("Test PASSED"); + } + + // lets search for a few possible locations using process output and return existing location + private static String getCoreFileLocation(String crashOutputString) { + Asserts.assertTrue(crashOutputString.contains(LOCATIONS_STRING), + "Output doesn't contain the location of core file."); + String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n")) + .filter(str -> str.contains(LOCATIONS_STRING)) + .findFirst() + .get(); + stringWithLocation = stringWithLocation.substring(stringWithLocation + .indexOf(LOCATIONS_STRING) + LOCATIONS_STRING.length()); + String coreWithPid; + if (stringWithLocation.contains("or ")) { + Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation); + if (!m.find()) { + throw new Error("Couldn't find path to core inside location string"); + } + coreWithPid = m.group(1); + } else { + coreWithPid = stringWithLocation.trim(); + } + if (new File(coreWithPid).exists()) { + return coreWithPid; + } + String justCore = Paths.get("core").toString(); + if (new File(justCore).exists()) { + return justCore; + } + Path coreWithPidPath = Paths.get(coreWithPid); + String justFile = coreWithPidPath.getFileName().toString(); + if (new File(justFile).exists()) { + return justFile; + } + Path parent = coreWithPidPath.getParent(); + if (parent != null) { + String coreWithoutPid = parent.resolve("core").toString(); + if (new File(coreWithoutPid).exists()) { + return coreWithoutPid; + } + } + return null; + } + + private static String[] getTestJavaCommandlineWithPrefix(String prefix, String... args) { + try { + String cmd = ProcessTools.getCommandLine(ProcessTools.createJavaProcessBuilder(true, args)); + return new String[]{"sh", "-c", prefix + cmd}; + } catch (Throwable t) { + throw new Error("Can't create process builder: " + t, t); + } + } + + private static void cleanup() { + remove(TEST_CDS_CORE_FILE_NAME); + remove(SHARED_ARCHIVE_NAME); + } + + private static void remove(String item) { + File toDelete = new File(item); + toDelete.delete(); + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSJstackPrintAll.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSJstackPrintAll.java new file mode 100644 index 00000000000..65a0b387e5b --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSJstackPrintAll.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174994 + * @summary Test the clhsdb commands 'jstack', 'printall' with CDS enabled + * @requires vm.cds + * @library /test/lib + * @run main/othervm/timeout=2400 -Xmx1g ClhsdbCDSJstackPrintAll + */ + +import java.util.List; +import java.util.Arrays; +import java.util.Map; +import java.util.HashMap; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.apps.LingeredApp; + +public class ClhsdbCDSJstackPrintAll { + + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbCDSJstackPrintAll test"); + String sharedArchiveName = "ArchiveForClhsdbJstackPrintAll.jsa"; + LingeredApp theApp = null; + + try { + CDSOptions opts = (new CDSOptions()).setArchiveName(sharedArchiveName); + CDSTestUtils.createArchiveAndCheck(opts); + + ClhsdbLauncher test = new ClhsdbLauncher(); + List vmArgs = Arrays.asList( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + sharedArchiveName, + "-Xshare:auto"); + theApp = LingeredApp.startApp(vmArgs); + System.out.println("Started LingeredApp with pid " + theApp.getPid()); + + // Ensure that UseSharedSpaces is turned on. + List cmds = List.of("flags UseSharedSpaces"); + + String useSharedSpacesOutput = test.run(theApp.getPid(), cmds, + null, null); + + if (useSharedSpacesOutput == null) { + // Attach permission issues. + System.out.println("Could not determine the UseSharedSpaces value - test skipped."); + LingeredApp.stopApp(theApp); + return; + } + + if (!useSharedSpacesOutput.contains("true")) { + // CDS archive is not mapped. Skip the rest of the test. + System.out.println("The CDS archive is not mapped - test skipped."); + LingeredApp.stopApp(theApp); + return; + } + + cmds = List.of("jstack -v", "printall"); + + Map> expStrMap = new HashMap<>(); + Map> unExpStrMap = new HashMap<>(); + expStrMap.put("jstack -v", List.of( + "No deadlocks found", + "Common-Cleaner", + "Signal Dispatcher", + "Method*", + "LingeredApp.main")); + unExpStrMap.put("jstack -v", List.of( + "sun.jvm.hotspot.types.WrongTypeException", + "No suitable match for type of address")); + expStrMap.put("printall", List.of( + "aload_0", + "Constant Pool of", + "public static void main(java.lang.String[])", + "Bytecode", + "invokevirtual", + "checkcast", + "Exception Table", + "invokedynamic")); + unExpStrMap.put("printall", List.of( + "No suitable match for type of address")); + test.run(theApp.getPid(), cmds, expStrMap, unExpStrMap); + } catch (Exception ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } finally { + LingeredApp.stopApp(theApp); + } + System.out.println("Test PASSED"); + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java index 246f4b1f743..bf8a499353f 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java @@ -29,6 +29,7 @@ import java.util.Map; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.Platform; import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.OutputAnalyzer; /** @@ -66,6 +67,27 @@ public class ClhsdbLauncher { toolProcess = processBuilder.start(); } + /** + * + * Launches 'jhsdb clhsdb' and loads a core file. + * @param coreFileName - Name of the corefile to be loaded. + */ + private void loadCore(String coreFileName) + throws IOException { + + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addToolArg("clhsdb"); + launcher.addToolArg("--core=" + coreFileName); + launcher.addToolArg("--exe=" + JDKToolFinder.getTestJDKTool("java")); + System.out.println("Starting clhsdb against corefile " + coreFileName + + " and exe " + JDKToolFinder.getTestJDKTool("java")); + + ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand()); + processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + + toolProcess = processBuilder.start(); + } + /** * * Runs 'jhsdb clhsdb' commands and checks for expected and unexpected strings. @@ -159,4 +181,32 @@ public class ClhsdbLauncher { attach(lingeredAppPid); return runCmd(commands, expectedStrMap, unExpectedStrMap); } + + /** + * + * Launches 'jhsdb clhsdb', loads a core file, executes the commands, + * checks for expected and unexpected strings. + * @param coreFileName - Name of the core file to be debugged. + * @param commands - clhsdb commands to execute. + * @param expectedStrMap - Map of expected strings per command which need to + * be checked in the output of the command. + * @param unExpectedStrMap - Map of unexpected strings per command which should + * not be present in the output of the command. + * @return Output of the commands as a String. + */ + public String runOnCore(String coreFileName, + List commands, + Map> expectedStrMap, + Map> unExpectedStrMap) + throws IOException, InterruptedException { + + if (!Platform.shouldSAAttach()) { + // Silently skip the test if we don't have enough permissions to attach + System.out.println("SA attach not expected to work - test skipped."); + return null; + } + + loadCore(coreFileName); + return runCmd(commands, expectedStrMap, unExpectedStrMap); + } } From 2df7aa7b9f8196897e33e0e34a8a6863fd3579db Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 26 Apr 2018 09:04:18 +0100 Subject: [PATCH 052/102] 8202261: (fc) FileChannel.map and RandomAccessFile.setLength should not preallocate space Reviewed-by: bpb --- .../classes/sun/nio/ch/FileChannelImpl.java | 15 ++--- .../classes/sun/nio/ch/FileDispatcher.java | 11 +++- .../sun/nio/ch/FileDispatcherImpl.java | 14 ++-- .../unix/native/libjava/io_util_md.c | 21 +----- .../unix/native/libnio/ch/FileChannelImpl.c | 41 ++++-------- .../native/libnio/ch/FileDispatcherImpl.c | 64 ++++++++----------- .../sun/nio/ch/FileDispatcherImpl.java | 16 ++--- .../native/libnio/ch/FileChannelImpl.c | 36 ++--------- .../native/libnio/ch/FileDispatcherImpl.c | 27 +++++++- 9 files changed, 101 insertions(+), 144 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 1ffb1ea0bfb..6e0bbc6d118 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -334,7 +334,7 @@ public class FileChannelImpl boolean append = fdAccess.getAppend(fd); do { // in append-mode then position is advanced to end before writing - p = (append) ? nd.size(fd) : position0(fd, -1); + p = (append) ? nd.size(fd) : nd.seek(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(p); } finally { @@ -358,7 +358,7 @@ public class FileChannelImpl if (!isOpen()) return null; do { - p = position0(fd, newPosition); + p = nd.seek(fd, newPosition); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { @@ -418,7 +418,7 @@ public class FileChannelImpl // get current position do { - p = position0(fd, -1); + p = nd.seek(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; @@ -437,7 +437,7 @@ public class FileChannelImpl if (p > newSize) p = newSize; do { - rp = position0(fd, p); + rp = nd.seek(fd, p); } while ((rp == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { @@ -985,7 +985,7 @@ public class FileChannelImpl } int rv; do { - rv = nd.allocate(fd, position + size); + rv = nd.truncate(fd, position + size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; @@ -1212,11 +1212,6 @@ public class FileChannelImpl private native long transferTo0(FileDescriptor src, long position, long count, FileDescriptor dst); - // Sets or reports this file's position - // If offset is -1, the current position is returned - // otherwise the position is set to offset - private native long position0(FileDescriptor fd, long offset); - // Caches fieldIDs private static native long initIDs(); diff --git a/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java b/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java index 3cf74c612a8..5089ab944d6 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java +++ b/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,12 +36,17 @@ abstract class FileDispatcher extends NativeDispatcher { public static final int RET_EX_LOCK = 1; // Obtained exclusive lock public static final int INTERRUPTED = 2; // Request interrupted + /** + * Sets or reports this file's position + * If offset is -1, the current position is returned + * otherwise the position is set to offset. + */ + abstract long seek(FileDescriptor fd, long offset) throws IOException; + abstract int force(FileDescriptor fd, boolean metaData) throws IOException; abstract int truncate(FileDescriptor fd, long size) throws IOException; - abstract int allocate(FileDescriptor fd, long size) throws IOException; - abstract long size(FileDescriptor fd) throws IOException; abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size, diff --git a/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java b/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java index 431d9396851..54a210c24e1 100644 --- a/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,10 @@ class FileDispatcherImpl extends FileDispatcher { return writev0(fd, address, len); } + long seek(FileDescriptor fd, long offset) throws IOException { + return seek0(fd, offset); + } + int force(FileDescriptor fd, boolean metaData) throws IOException { return force0(fd, metaData); } @@ -82,10 +86,6 @@ class FileDispatcherImpl extends FileDispatcher { return truncate0(fd, size); } - int allocate(FileDescriptor fd, long size) throws IOException { - return allocate0(fd, size); - } - long size(FileDescriptor fd) throws IOException { return size0(fd); } @@ -156,10 +156,10 @@ class FileDispatcherImpl extends FileDispatcher { static native int force0(FileDescriptor fd, boolean metaData) throws IOException; - static native int truncate0(FileDescriptor fd, long size) + static native long seek0(FileDescriptor fd, long offset) throws IOException; - static native int allocate0(FileDescriptor fd, long size) + static native int truncate0(FileDescriptor fd, long size) throws IOException; static native long size0(FileDescriptor fd) throws IOException; diff --git a/src/java.base/unix/native/libjava/io_util_md.c b/src/java.base/unix/native/libjava/io_util_md.c index 1ec21237856..8a4899740f4 100644 --- a/src/java.base/unix/native/libjava/io_util_md.c +++ b/src/java.base/unix/native/libjava/io_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,25 +232,6 @@ jint handleSetLength(FD fd, jlong length) { int result; -#if defined(__linux__) - /* - * On Linux, if the file size is being increased, then ftruncate64() - * will modify the metadata value of the size without actually allocating - * any blocks which can cause a SIGBUS error if the file is subsequently - * memory-mapped. - */ - struct stat64 sb; - - if (fstat64(fd, &sb) == 0 && length > sb.st_blocks*512) { - RESTARTABLE(fallocate64(fd, 0, 0, length), result); - // Return on success or if errno is neither EOPNOTSUPP nor ENOSYS - if (result == 0) { - return 0; - } else if (errno != EOPNOTSUPP && errno != ENOSYS) { - return result; - } - } -#endif RESTARTABLE(ftruncate64(fd, length), result); return result; } diff --git a/src/java.base/unix/native/libnio/ch/FileChannelImpl.c b/src/java.base/unix/native/libnio/ch/FileChannelImpl.c index a3c2ac91fd5..77ec3d402fe 100644 --- a/src/java.base/unix/native/libnio/ch/FileChannelImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,33 +23,31 @@ * questions. */ -#include "jni.h" -#include "jni_util.h" -#include "jvm.h" -#include "jvm_md.h" -#include "jlong.h" #include #include #include -#include "sun_nio_ch_FileChannelImpl.h" -#include "java_lang_Integer.h" -#include "nio.h" -#include "nio_util.h" -#include +#include +#include #if defined(__linux__) || defined(__solaris__) #include #elif defined(_AIX) #include #elif defined(_ALLBSD_SOURCE) -#include #include #include - #define lseek64 lseek #define mmap64 mmap #endif +#include "jni.h" +#include "jni_util.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" +#include "sun_nio_ch_FileChannelImpl.h" +#include "java_lang_Integer.h" + static jfieldID chan_fd; /* jobject 'fd' in sun.nio.ch.FileChannelImpl */ JNIEXPORT jlong JNICALL @@ -123,23 +121,6 @@ Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, "Unmap failed"); } - -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, - jobject fdo, jlong offset) -{ - jint fd = fdval(env, fdo); - jlong result = 0; - - if (offset < 0) { - result = lseek64(fd, 0, SEEK_CUR); - } else { - result = lseek64(fd, offset, SEEK_SET); - } - return handle(env, result, "Position failed"); -} - - JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, jobject srcFDO, diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c index 098535db7d6..e31142ad36d 100644 --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,40 +23,42 @@ * questions. */ -#include "jni.h" -#include "jni_util.h" -#include "jvm.h" -#include "jlong.h" -#include "sun_nio_ch_FileDispatcherImpl.h" -#include "java_lang_Long.h" #include #include #include #include #include +#include #include + #if defined(__linux__) #include #include #endif -#include "nio.h" -#include "nio_util.h" -#ifdef _ALLBSD_SOURCE +#if defined(_ALLBSD_SOURCE) +#define lseek64 lseek #define stat64 stat #define flock64 flock #define off64_t off_t #define F_SETLKW64 F_SETLKW #define F_SETLK64 F_SETLK - #define pread64 pread #define pwrite64 pwrite #define ftruncate64 ftruncate #define fstat64 fstat - #define fdatasync fsync #endif +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" +#include "sun_nio_ch_FileDispatcherImpl.h" +#include "java_lang_Long.h" + static int preCloseFD = -1; /* File descriptor to which we dup other fd's before closing them for real */ @@ -142,6 +144,20 @@ handle(JNIEnv *env, jlong rv, char *msg) return IOS_THROWN; } +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz, + jobject fdo, jlong offset) +{ + jint fd = fdval(env, fdo); + off64_t result; + if (offset < 0) { + result = lseek64(fd, 0, SEEK_CUR); + } else { + result = lseek64(fd, offset, SEEK_SET); + } + return handle(env, (jlong)result, "lseek64 failed"); +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, jobject fdo, jboolean md) @@ -187,30 +203,6 @@ Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this, "Truncation failed"); } -JNIEXPORT jint JNICALL -Java_sun_nio_ch_FileDispatcherImpl_allocate0(JNIEnv *env, jobject this, - jobject fdo, jlong size) -{ -#if defined(__linux__) - /* - * On Linux, if the file size is being increased, then ftruncate64() - * will modify the metadata value of the size without actually allocating - * any blocks which can cause a SIGBUS error if the file is subsequently - * memory-mapped. - */ - // Return on success or if errno is neither EOPNOTSUPP nor ENOSYS - int result = fallocate64(fdval(env, fdo), 0, 0, size); - if (result == 0) { - return 0; - } else if (errno != EOPNOTSUPP && errno != ENOSYS) { - return handle(env, result, "Allocation failed"); - } -#endif - return handle(env, - ftruncate64(fdval(env, fdo), size), - "Truncation failed"); -} - JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) { diff --git a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java index 9424d36f892..bc35a5d710f 100644 --- a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,6 +78,10 @@ class FileDispatcherImpl extends FileDispatcher { return writev0(fd, address, len, fdAccess.getAppend(fd)); } + long seek(FileDescriptor fd, long offset) throws IOException { + return seek0(fd, offset); + } + int force(FileDescriptor fd, boolean metaData) throws IOException { return force0(fd, metaData); } @@ -86,11 +90,6 @@ class FileDispatcherImpl extends FileDispatcher { return truncate0(fd, size); } - int allocate(FileDescriptor fd, long size) throws IOException { - // truncate0() works for extending and truncating file size - return truncate0(fd, size); - } - long size(FileDescriptor fd) throws IOException { return size0(fd); } @@ -126,8 +125,7 @@ class FileDispatcherImpl extends FileDispatcher { return true; } - int setDirectIO(FileDescriptor fd, String path) - { + int setDirectIO(FileDescriptor fd, String path) { int result = -1; String filePath = path.substring(0, path.lastIndexOf(File.separator)); CharBuffer buffer = CharBuffer.allocate(filePath.length()); @@ -178,6 +176,8 @@ class FileDispatcherImpl extends FileDispatcher { static native long writev0(FileDescriptor fd, long address, int len, boolean append) throws IOException; + static native long seek0(FileDescriptor fd, long offset) throws IOException; + static native int force0(FileDescriptor fd, boolean metaData) throws IOException; diff --git a/src/java.base/windows/native/libnio/ch/FileChannelImpl.c b/src/java.base/windows/native/libnio/ch/FileChannelImpl.c index 28d5f9ec8b9..c2fb913f1b6 100644 --- a/src/java.base/windows/native/libnio/ch/FileChannelImpl.c +++ b/src/java.base/windows/native/libnio/ch/FileChannelImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,31 +140,6 @@ Java_sun_nio_ch_FileChannelImpl_unmap0(JNIEnv *env, jobject this, return 0; } -JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this, - jobject fdo, jlong offset) -{ - BOOL result = 0; - HANDLE h = (HANDLE)(handleval(env, fdo)); - LARGE_INTEGER where; - DWORD whence; - - if (offset < 0) { - where.QuadPart = 0; - whence = FILE_CURRENT; - } else { - where.QuadPart = offset; - whence = FILE_BEGIN; - } - - result = SetFilePointerEx(h, where, &where, whence); - if (result == 0) { - JNU_ThrowIOExceptionWithLastError(env, "Seek failed"); - return IOS_THROWN; - } - return (jlong)where.QuadPart; -} - JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, jobject srcFD, @@ -173,14 +148,17 @@ Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this, { const int PACKET_SIZE = 524288; + LARGE_INTEGER where; HANDLE src = (HANDLE)(handleval(env, srcFD)); SOCKET dst = (SOCKET)(fdval(env, dstFD)); DWORD chunkSize = (count > java_lang_Integer_MAX_VALUE) ? java_lang_Integer_MAX_VALUE : (DWORD)count; - BOOL result = 0; + BOOL result; - jlong pos = Java_sun_nio_ch_FileChannelImpl_position0(env, this, srcFD, position); - if (pos == IOS_THROWN) { + where.QuadPart = position; + result = SetFilePointerEx(src, where, &where, FILE_BEGIN); + if (result == 0) { + JNU_ThrowIOExceptionWithLastError(env, "SetFilePointerEx failed"); return IOS_THROWN; } diff --git a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c index 296ff597f63..3eeacf279c5 100644 --- a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,6 +298,31 @@ Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fd return convertReturnVal(env, (jint)written, JNI_FALSE); } +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_FileDispatcherImpl_seek0(JNIEnv *env, jclass clazz, + jobject fdo, jlong offset) +{ + BOOL result = 0; + HANDLE h = (HANDLE)(handleval(env, fdo)); + LARGE_INTEGER where; + DWORD whence; + + if (offset < 0) { + where.QuadPart = 0; + whence = FILE_CURRENT; + } else { + where.QuadPart = offset; + whence = FILE_BEGIN; + } + + result = SetFilePointerEx(h, where, &where, whence); + if (result == 0) { + JNU_ThrowIOExceptionWithLastError(env, "SetFilePointerEx failed"); + return IOS_THROWN; + } + return (jlong)where.QuadPart; +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this, jobject fdo, jboolean md) From 4e252915c5cdfc4491ed215b50ec559dd0de478a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Thu, 26 Apr 2018 11:56:24 +0200 Subject: [PATCH 053/102] 8200235: Generalize jniFastGetField jobject/jweak resolve Reviewed-by: kbarrett, dholmes --- .../gc/shared/barrierSetAssembler_aarch64.cpp | 8 ++++++++ .../gc/shared/barrierSetAssembler_aarch64.hpp | 2 ++ .../cpu/aarch64/jniFastGetField_aarch64.cpp | 9 ++++----- .../gc/shared/barrierSetAssembler_sparc.cpp | 6 ++++++ .../gc/shared/barrierSetAssembler_sparc.hpp | 3 +++ src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp | 17 ++++++++++------- .../x86/gc/shared/barrierSetAssembler_x86.cpp | 6 ++++++ .../x86/gc/shared/barrierSetAssembler_x86.hpp | 3 +++ src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp | 8 +++++--- 9 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 042ed44e974..ca3985ebe66 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/barrierSetAssembler.hpp" +#include "runtime/jniHandles.hpp" #define __ masm-> @@ -64,3 +65,10 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators default: Unimplemented(); } } + +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath) { + // If mask changes we need to ensure that the inverse is still encodable as an immediate + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); + __ andr(robj, robj, ~JNIHandles::weak_tag_mask); + __ ldr(robj, Address(robj, 0)); // *obj +} diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index 2ef79379742..6c6bed5d89a 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -40,6 +40,8 @@ public: virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath); + virtual void barrier_stubs_init() {} }; diff --git a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp index b0f9acee633..d189a4697ae 100644 --- a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp @@ -25,6 +25,8 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" #include "memory/resourceArea.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" @@ -82,11 +84,9 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { // robj ^ rcounter ^ rcounter == robj // robj is address dependent on rcounter. - // If mask changes we need to ensure that the inverse is still encodable as an immediate - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); - __ andr(robj, robj, ~JNIHandles::weak_tag_mask); + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->try_resolve_jobject_in_native(masm, robj, rscratch1, slow); - __ ldr(robj, Address(robj, 0)); // *obj __ lsr(roffset, c_rarg2, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); @@ -177,4 +177,3 @@ address JNI_FastGetField::generate_fast_get_float_field() { address JNI_FastGetField::generate_fast_get_double_field() { return generate_fast_get_int_field0(T_DOUBLE); } - diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp index 5b8765ab983..410da25f3cc 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "interpreter/interp_masm.hpp" +#include "runtime/jniHandles.hpp" #define __ masm-> @@ -98,3 +99,8 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, default: Unimplemented(); } } + +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath) { + __ andn (robj, JNIHandles::weak_tag_mask, robj); + __ ld_ptr(robj, 0, robj); +} diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp index e6dd54d2abc..17546735cc8 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp @@ -44,6 +44,9 @@ public: virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address src, Register dst, Register tmp); + // Support for jniFastGetField to try resolving a jobject/jweak in native + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath); + virtual void barrier_stubs_init() {} }; diff --git a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp b/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp index 178b9c74870..c1c4e2863b0 100644 --- a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp +++ b/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" #include "memory/resourceArea.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" @@ -68,17 +70,18 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); - __ andn (O1, JNIHandles::weak_tag_mask, O1); - __ ld_ptr (O1, 0, O5); + + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->try_resolve_jobject_in_native(masm, O1, G3_scratch, label1); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); switch (type) { - case T_BOOLEAN: __ ldub (O5, O4, G3); break; - case T_BYTE: __ ldsb (O5, O4, G3); break; - case T_CHAR: __ lduh (O5, O4, G3); break; - case T_SHORT: __ ldsh (O5, O4, G3); break; - case T_INT: __ ld (O5, O4, G3); break; + case T_BOOLEAN: __ ldub (O1, O4, G3); break; + case T_BYTE: __ ldsb (O1, O4, G3); break; + case T_CHAR: __ lduh (O1, O4, G3); break; + case T_SHORT: __ ldsh (O1, O4, G3); break; + case T_INT: __ ld (O1, O4, G3); break; default: ShouldNotReachHere(); } diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 19fcf9e83ad..271caf9f374 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "interpreter/interp_masm.hpp" +#include "runtime/jniHandles.hpp" #define __ masm-> @@ -108,3 +109,8 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators default: Unimplemented(); } } + +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath) { + __ clear_jweak_tag(robj); + __ movptr(robj, Address(robj, 0)); +} diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index 348fc80726d..35030b68a51 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -44,6 +44,9 @@ public: virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); + // Support for jniFastGetField to try resolving a jobject/jweak in native + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath); + virtual void barrier_stubs_init() {} }; diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp index b078bcf2db3..b28ff9ff708 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" #include "memory/resourceArea.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp" @@ -81,12 +83,12 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { // robj is data dependent on rcounter. } - __ clear_jweak_tag(robj); - - __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->try_resolve_jobject_in_native(masm, robj, rscratch1, slow); + assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); switch (type) { From a7b8407fbc2cfedd272600811a286022ad8def33 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 26 Apr 2018 09:04:09 -0400 Subject: [PATCH 054/102] 8197960: [TESTBUG] remove/modify runtime tests which use java ee or corba modules Replace references to java ee and corba modules with module java.sql. Reviewed-by: lfoltan, ccheung --- test/hotspot/jtreg/ProblemList.txt | 1 - .../PatchModule/PatchModuleClassList.java | 34 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d1e90578a00..d6427408fc0 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -92,6 +92,5 @@ serviceability/sa/sadebugd/SADebugDTest.java 8163805 generic-all # Java EE Module Removal # -runtime/modules/PatchModule/PatchModuleClassList.java 8194310 generic-all Java EE Module Removal compiler/c2/Test8007294.java 8194310 generic-all Java EE Module Removal compiler/c2/Test6852078.java 8194310 generic-all Java EE Module Removal diff --git a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleClassList.java b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleClassList.java index 5808d377a86..2c4442c7c91 100644 --- a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleClassList.java +++ b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleClassList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import jdk.test.lib.process.ProcessTools; public class PatchModuleClassList { private static final String BOOT_CLASS = "javax/naming/spi/NamingManager"; - private static final String PLATFORM_CLASS = "javax/transaction/InvalidTransactionException"; + private static final String PLATFORM_CLASS = "java/sql/ResultSet"; public static void main(String args[]) throws Throwable { // Case 1. A class to be loaded by the boot class loader @@ -68,7 +68,9 @@ public class PatchModuleClassList { "-XX:DumpLoadedClassList=" + classList, "--patch-module=java.naming=" + moduleJar, "PatchModuleMain", BOOT_CLASS.replace('/', '.')); - new OutputAnalyzer(pb.start()).shouldHaveExitValue(0); + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + oa.shouldContain("I pass!"); + oa.shouldHaveExitValue(0); // check the generated classlist file String content = new String(Files.readAllBytes(Paths.get(classList))); @@ -78,30 +80,32 @@ public class PatchModuleClassList { // Case 2. A class to be loaded by the platform class loader - // Create a class file in the module java.transaction. This class file - // will be put in the javatransaction.jar file. - source = "package javax.transaction; " + - "public class InvalidTransactionException { " + + // Create a class file in the module java.sql. This class file + // will be put in the javasql.jar file. + source = "package java.sql; " + + "public class ResultSet { " + " static { " + - " System.out.println(\"I pass!\"); " + + " System.out.println(\"I pass too!\"); " + " } " + "}"; ClassFileInstaller.writeClassToDisk(PLATFORM_CLASS, - InMemoryJavaCompiler.compile(PLATFORM_CLASS.replace('/', '.'), source, "--patch-module=java.transaction"), + InMemoryJavaCompiler.compile(PLATFORM_CLASS.replace('/', '.'), source, "--patch-module=java.sql"), System.getProperty("test.classes")); - // Build the jar file that will be used for the module "java.transaction". - BasicJarBuilder.build("javatransaction", PLATFORM_CLASS); - moduleJar = BasicJarBuilder.getTestJar("javatransaction.jar"); + // Build the jar file that will be used for the module "java.sql". + BasicJarBuilder.build("javasql", PLATFORM_CLASS); + moduleJar = BasicJarBuilder.getTestJar("javasql.jar"); - classList = "javatransaction.list"; + classList = "javasql.list"; pb = ProcessTools.createJavaProcessBuilder( true, "-XX:DumpLoadedClassList=" + classList, - "--patch-module=java.naming=" + moduleJar, + "--patch-module=java.sql=" + moduleJar, "PatchModuleMain", PLATFORM_CLASS.replace('/', '.')); - new OutputAnalyzer(pb.start()).shouldHaveExitValue(0); + OutputAnalyzer oa2 = new OutputAnalyzer(pb.start()); + oa2.shouldContain("I pass too!"); + oa2.shouldHaveExitValue(0); // check the generated classlist file content = new String(Files.readAllBytes(Paths.get(classList))); From dce2872700c98c70bdc44cc29863933d33f45172 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 26 Apr 2018 17:14:04 +0200 Subject: [PATCH 055/102] 8202324: Avoid loading FileInput-/OutputStream$AltFinalizer Reviewed-by: alanb --- .../classes/java/io/FileInputStream.java | 41 +++++++++--------- .../classes/java/io/FileOutputStream.java | 42 +++++++++---------- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index 32a386aafda..a2ab728ab9b 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -79,7 +79,7 @@ class FileInputStream extends InputStream private volatile boolean closed; - private final AltFinalizer altFinalizer; + private final Object altFinalizer; /** * Creates a FileInputStream by @@ -155,7 +155,7 @@ class FileInputStream extends InputStream fd.attach(this); path = name; open(name); - altFinalizer = AltFinalizer.get(this); + altFinalizer = getFinalizer(this); if (altFinalizer == null) { FileCleanable.register(fd); // open set the fd, register the cleanup } @@ -471,6 +471,23 @@ class FileInputStream extends InputStream protected void finalize() throws IOException { } + /* + * Returns a finalizer object if the FIS needs a finalizer; otherwise null. + * If the FIS has a close method; it needs an AltFinalizer. + */ + private static Object getFinalizer(FileInputStream fis) { + Class clazz = fis.getClass(); + while (clazz != FileInputStream.class) { + try { + clazz.getDeclaredMethod("close"); + return new AltFinalizer(fis); + } catch (NoSuchMethodException nsme) { + // ignore + } + clazz = clazz.getSuperclass(); + } + return null; + } /** * Class to call {@code FileInputStream.close} when finalized. * If finalization of the stream is needed, an instance is created @@ -481,25 +498,7 @@ class FileInputStream extends InputStream static class AltFinalizer { private final FileInputStream fis; - /* - * Returns a finalizer object if the FIS needs a finalizer; otherwise null. - * If the FIS has a close method; it needs an AltFinalizer. - */ - static AltFinalizer get(FileInputStream fis) { - Class clazz = fis.getClass(); - while (clazz != FileInputStream.class) { - try { - clazz.getDeclaredMethod("close"); - return new AltFinalizer(fis); - } catch (NoSuchMethodException nsme) { - // ignore - } - clazz = clazz.getSuperclass(); - } - return null; - } - - private AltFinalizer(FileInputStream fis) { + AltFinalizer(FileInputStream fis) { this.fis = fis; } diff --git a/src/java.base/share/classes/java/io/FileOutputStream.java b/src/java.base/share/classes/java/io/FileOutputStream.java index 37338423aa1..569f5269b13 100644 --- a/src/java.base/share/classes/java/io/FileOutputStream.java +++ b/src/java.base/share/classes/java/io/FileOutputStream.java @@ -95,7 +95,7 @@ class FileOutputStream extends OutputStream private volatile boolean closed; - private final AltFinalizer altFinalizer; + private final Object altFinalizer; /** * Creates a file output stream to write to the file with the @@ -235,7 +235,7 @@ class FileOutputStream extends OutputStream this.path = name; open(name, append); - altFinalizer = AltFinalizer.get(this); + altFinalizer = getFinalizer(this); if (altFinalizer == null) { FileCleanable.register(fd); // open sets the fd, register the cleanup } @@ -496,6 +496,24 @@ class FileOutputStream extends OutputStream initIDs(); } + /* + * Returns a finalizer object if the FOS needs a finalizer; otherwise null. + * If the FOS has a close method; it needs an AltFinalizer. + */ + private static Object getFinalizer(FileOutputStream fos) { + Class clazz = fos.getClass(); + while (clazz != FileOutputStream.class) { + try { + clazz.getDeclaredMethod("close"); + return new AltFinalizer(fos); + } catch (NoSuchMethodException nsme) { + // ignore + } + clazz = clazz.getSuperclass(); + } + return null; + } + /** * Class to call {@code FileOutputStream.close} when finalized. * If finalization of the stream is needed, an instance is created @@ -506,25 +524,7 @@ class FileOutputStream extends OutputStream static class AltFinalizer { private final FileOutputStream fos; - /* - * Returns a finalizer object if the FOS needs a finalizer; otherwise null. - * If the FOS has a close method; it needs an AltFinalizer. - */ - static AltFinalizer get(FileOutputStream fos) { - Class clazz = fos.getClass(); - while (clazz != FileOutputStream.class) { - try { - clazz.getDeclaredMethod("close"); - return new AltFinalizer(fos); - } catch (NoSuchMethodException nsme) { - // ignore - } - clazz = clazz.getSuperclass(); - } - return null; - } - - private AltFinalizer(FileOutputStream fos) { + AltFinalizer(FileOutputStream fos) { this.fos = fos; } From 4d841c90fb1ede30e31da1c28046504d70f097ac Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Thu, 26 Apr 2018 09:10:04 -0700 Subject: [PATCH 056/102] 8202330: Add Unreferenced{FOS,FIS,RAF}ClosesFd to problem list Reviewed-by: alanb, bpb --- test/jdk/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index a533e8bb04c..14fa4bcf0ae 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -513,6 +513,9 @@ java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8081652 generic- java/io/FileOutputStream/AtomicAppend.java 8202062 macosx-all java/io/pathNames/GeneralWin32.java 8180264 windows-all +java/io/FileInputStream/UnreferencedFISClosesFd.java 8202292 linux-all +java/io/FileOutputStream/UnreferencedFOSClosesFd.java 8202292 linux-all +java/io/RandomAccessFile/UnreferencedRAFClosesFd.java 8202292 linux-all ############################################################################ From edc81d17e1efaca5e7c1d9d3c68c60738bb8c0a1 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Thu, 26 Apr 2018 11:19:05 -0500 Subject: [PATCH 057/102] 8202150: [REDO] Split globals.hpp to factor out the Flag class Factored out Flag out go globals, renamed to JVMFlag Reviewed-by: coleenp, dholmes, kvn --- .../cpu/aarch64/methodHandles_aarch64.cpp | 1 + .../cpu/sparc/macroAssembler_sparc.cpp | 1 + src/hotspot/cpu/sparc/methodHandles_sparc.cpp | 1 + src/hotspot/cpu/x86/macroAssembler_x86.cpp | 1 + src/hotspot/cpu/x86/methodHandles_x86.cpp | 1 + src/hotspot/share/code/dependencies.cpp | 1 + src/hotspot/share/code/nmethod.cpp | 1 + src/hotspot/share/code/relocInfo.cpp | 3 +- .../gc/cms/concurrentMarkSweepGeneration.cpp | 1 + ...aintsCMS.cpp => jvmFlagConstraintsCMS.cpp} | 88 +- ...aintsCMS.hpp => jvmFlagConstraintsCMS.hpp} | 26 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 + ...traintsG1.cpp => jvmFlagConstraintsG1.cpp} | 64 +- ...traintsG1.hpp => jvmFlagConstraintsG1.hpp} | 18 +- ...lel.cpp => jvmFlagConstraintsParallel.cpp} | 20 +- ...lel.hpp => jvmFlagConstraintsParallel.hpp} | 6 +- src/hotspot/share/gc/parallel/psMarkSweep.cpp | 1 + .../shared/commandLineFlagConstraintsGC.hpp | 73 - .../share/gc/shared/genCollectedHeap.cpp | 1 + ...traintsGC.cpp => jvmFlagConstraintsGC.cpp} | 202 +-- .../share/gc/shared/jvmFlagConstraintsGC.hpp | 73 + src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 3 +- .../share/jvmci/jvmciCompilerToVMInit.cpp | 5 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 23 +- src/hotspot/share/memory/universe.cpp | 5 +- src/hotspot/share/oops/klassVtable.cpp | 1 + src/hotspot/share/precompiled/precompiled.hpp | 11 + src/hotspot/share/prims/whitebox.cpp | 57 +- src/hotspot/share/runtime/arguments.cpp | 236 +-- src/hotspot/share/runtime/arguments.hpp | 7 +- .../runtime/commandLineFlagConstraintList.hpp | 101 -- .../commandLineFlagConstraintsCompiler.hpp | 75 - .../share/runtime/flags/flagSetting.hpp | 71 + src/hotspot/share/runtime/flags/jvmFlag.cpp | 1506 +++++++++++++++++ src/hotspot/share/runtime/flags/jvmFlag.hpp | 283 ++++ .../jvmFlagConstraintList.cpp} | 184 +- .../runtime/flags/jvmFlagConstraintList.hpp | 101 ++ .../jvmFlagConstraintsCompiler.cpp} | 133 +- .../flags/jvmFlagConstraintsCompiler.hpp | 74 + .../jvmFlagConstraintsRuntime.cpp} | 57 +- .../jvmFlagConstraintsRuntime.hpp} | 25 +- .../jvmFlagRangeList.cpp} | 143 +- .../jvmFlagRangeList.hpp} | 40 +- .../jvmFlagWriteableList.cpp} | 62 +- .../jvmFlagWriteableList.hpp} | 23 +- src/hotspot/share/runtime/globals.cpp | 1476 +--------------- src/hotspot/share/runtime/globals.hpp | 347 +--- src/hotspot/share/runtime/globals_ext.hpp | 22 +- .../share/runtime/globals_extension.hpp | 55 +- src/hotspot/share/runtime/handshake.hpp | 1 + src/hotspot/share/runtime/init.cpp | 4 +- src/hotspot/share/runtime/java.cpp | 1 + src/hotspot/share/runtime/mutexLocker.hpp | 1 + src/hotspot/share/runtime/thread.cpp | 13 +- src/hotspot/share/runtime/vmStructs.cpp | 29 +- src/hotspot/share/services/attachListener.cpp | 9 +- .../share/services/diagnosticCommand.cpp | 10 +- src/hotspot/share/services/dtraceAttacher.cpp | 7 +- src/hotspot/share/services/management.cpp | 41 +- src/hotspot/share/services/writeableFlags.cpp | 119 +- src/hotspot/share/services/writeableFlags.hpp | 43 +- src/hotspot/share/utilities/debug.cpp | 1 + .../share/utilities/globalDefinitions.hpp | 7 + .../classes/sun/jvm/hotspot/runtime/VM.java | 4 +- .../gtest/gc/shared/test_collectorPolicy.cpp | 3 +- test/hotspot/gtest/runtime/test_globals.cpp | 21 +- 66 files changed, 3060 insertions(+), 2964 deletions(-) rename src/hotspot/share/gc/cms/{commandLineFlagConstraintsCMS.cpp => jvmFlagConstraintsCMS.cpp} (78%) rename src/hotspot/share/gc/cms/{commandLineFlagConstraintsCMS.hpp => jvmFlagConstraintsCMS.hpp} (60%) rename src/hotspot/share/gc/g1/{commandLineFlagConstraintsG1.cpp => jvmFlagConstraintsG1.cpp} (76%) rename src/hotspot/share/gc/g1/{commandLineFlagConstraintsG1.hpp => jvmFlagConstraintsG1.hpp} (67%) rename src/hotspot/share/gc/parallel/{commandLineFlagConstraintsParallel.cpp => jvmFlagConstraintsParallel.cpp} (82%) rename src/hotspot/share/gc/parallel/{commandLineFlagConstraintsParallel.hpp => jvmFlagConstraintsParallel.hpp} (84%) delete mode 100644 src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp rename src/hotspot/share/gc/shared/{commandLineFlagConstraintsGC.cpp => jvmFlagConstraintsGC.cpp} (71%) create mode 100644 src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp delete mode 100644 src/hotspot/share/runtime/commandLineFlagConstraintList.hpp delete mode 100644 src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp create mode 100644 src/hotspot/share/runtime/flags/flagSetting.hpp create mode 100644 src/hotspot/share/runtime/flags/jvmFlag.cpp create mode 100644 src/hotspot/share/runtime/flags/jvmFlag.hpp rename src/hotspot/share/runtime/{commandLineFlagConstraintList.cpp => flags/jvmFlagConstraintList.cpp} (58%) create mode 100644 src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp rename src/hotspot/share/runtime/{commandLineFlagConstraintsCompiler.cpp => flags/jvmFlagConstraintsCompiler.cpp} (80%) create mode 100644 src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp rename src/hotspot/share/runtime/{commandLineFlagConstraintsRuntime.cpp => flags/jvmFlagConstraintsRuntime.cpp} (77%) rename src/hotspot/share/runtime/{commandLineFlagConstraintsRuntime.hpp => flags/jvmFlagConstraintsRuntime.hpp} (60%) rename src/hotspot/share/runtime/{commandLineFlagRangeList.cpp => flags/jvmFlagRangeList.cpp} (75%) rename src/hotspot/share/runtime/{commandLineFlagRangeList.hpp => flags/jvmFlagRangeList.hpp} (56%) rename src/hotspot/share/runtime/{commandLineFlagWriteableList.cpp => flags/jvmFlagWriteableList.cpp} (76%) rename src/hotspot/share/runtime/{commandLineFlagWriteableList.hpp => flags/jvmFlagWriteableList.hpp} (70%) diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index e717c1e7e96..8ae90a5f2c3 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -30,6 +30,7 @@ #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" #include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #define __ _masm-> diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp index b4a3052a998..f2e1c901b02 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp @@ -35,6 +35,7 @@ #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/objectMonitor.hpp" diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp index 6076f7ab053..f84ba5d0021 100644 --- a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp +++ b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp @@ -31,6 +31,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 43265c8acb2..15181a5d39e 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -37,6 +37,7 @@ #include "oops/klass.inline.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index e38515a6e7a..dc53107c735 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -31,6 +31,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 03c0ec89318..1c97270a030 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -35,6 +35,7 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2524af406c9..30b76407897 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -47,6 +47,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiImpl.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 16e2ab8d849..94fb1886b68 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "code/relocInfo.hpp" #include "memory/resourceArea.hpp" #include "oops/compressedOops.inline.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/copy.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp index a4d4c2facf6..8efe5dde48b 100644 --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp @@ -68,6 +68,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp similarity index 78% rename from src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp rename to src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp index 367f4e49e82..777ed6ce13d 100644 --- a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp +++ b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.cpp @@ -23,52 +23,52 @@ */ #include "precompiled.hpp" -#include "gc/cms/commandLineFlagConstraintsCMS.hpp" +#include "gc/cms/jvmFlagConstraintsCMS.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/commandLineFlagConstraintsGC.hpp" +#include "gc/shared/jvmFlagConstraintsGC.hpp" #include "memory/universe.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "utilities/globalDefinitions.hpp" -static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { +static JVMFlag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { // CMSWorkQueueDrainThreshold is verified to be less than max_juint if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { CommandLineError::print(verbose, "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" UINTX_FORMAT ") is too large\n", threads, threshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) { +JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) { // To avoid overflow at ParScanClosure::do_oop_work. if (UseConcMarkSweepGC && (value > (max_jint / 10))) { CommandLineError::print(verbose, "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for CMS GC\n", value, (max_jint / 10)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose); } -Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) { CommandLineError::print(verbose, "ParGCStridesPerThread (" UINTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", value, ((uintx)max_jint / (uintx)ParallelGCThreads)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { +JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { if (UseConcMarkSweepGC) { // ParGCCardsPerStrideChunk should be compared with card table size. size_t heap_size = Universe::heap()->reserved_region().word_size(); @@ -80,7 +80,7 @@ Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and " "must be less than or equal to card table size (" SIZE_FORMAT ")\n", value, card_table_size); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread) @@ -93,14 +93,14 @@ Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) { "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", value, ergo_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; if (UseConcMarkSweepGC) { if (value > CMSOldPLABMax) { @@ -108,15 +108,15 @@ Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { "CMSOldPLABMin (" SIZE_FORMAT ") must be " "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", value, CMSOldPLABMax); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); } return status; } -Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; if (UseConcMarkSweepGC) { status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); @@ -124,7 +124,7 @@ Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { return status; } -static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { +static JVMFlag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { if (UseConcMarkSweepGC) { ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen(); const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size(); @@ -134,17 +134,17 @@ static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, "less than or equal to ergonomic maximum (" SIZE_FORMAT ") " "which is based on the maximum size of the old generation of the Java heap\n", name, value, ergo_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { - Flag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); +JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); - if (status == Flag::SUCCESS && UseConcMarkSweepGC) { + if (status == JVMFlag::SUCCESS && UseConcMarkSweepGC) { // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size() // to be aligned to CardTable::card_size * BitsPerWord. // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize' @@ -154,40 +154,40 @@ Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { "CMSRescanMultiple (" SIZE_FORMAT ") must be " "a multiple of " SIZE_FORMAT "\n", value, HeapWordSize); - status = Flag::VIOLATES_CONSTRAINT; + status = JVMFlag::VIOLATES_CONSTRAINT; } } return status; } -Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose); } -Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { CommandLineError::print(verbose, "CMSPrecleanDenominator (" UINTX_FORMAT ") must be " "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n", value, CMSPrecleanNumerator); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) { CommandLineError::print(verbose, "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n", value, CMSPrecleanDenominator); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC) { size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity(); if (value > max_uintx - max_capacity) { @@ -195,20 +195,20 @@ Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) { "CMSSamplingGrain (" UINTX_FORMAT ") must be " "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n", value, max_uintx - max_capacity); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { if (UseConcMarkSweepGC) { return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose); } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { // Skip for current default value. if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) { // CMSBitMapYieldQuantum should be compared with mark bitmap size. @@ -221,18 +221,18 @@ Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) { "be less than or equal to bitmap size (" SIZE_FORMAT ") " "whose size corresponds to the size of old generation of the Java heap\n", value, bitmap_size); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { +JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) { if (value == 0) { CommandLineError::print(verbose, "OldPLABSize (" SIZE_FORMAT ") must be greater than 0", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // For CMS, OldPLABSize is the number of free blocks of a given size that are used when // replenishing the local per-worker free list caches. diff --git a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp similarity index 60% rename from src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp rename to src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp index c147e92de99..eabb9fc3933 100644 --- a/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp +++ b/src/hotspot/share/gc/cms/jvmFlagConstraintsCMS.hpp @@ -29,20 +29,20 @@ #include "utilities/globalDefinitions.hpp" // CMS Flag Constraints -Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); -Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); -Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); -Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); -Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); -Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); -Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); -Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); -Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); -Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); -Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); +JVMFlag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); +JVMFlag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); +JVMFlag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); +JVMFlag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +JVMFlag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose); // CMS Subconstraints -Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose); -Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose); +JVMFlag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose); +JVMFlag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose); #endif // SHARE_GC_CMS_COMMANDLINEFLAGCONSTRAINTSCMS_HPP diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 246714c512b..4078ff9bfa5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -84,6 +84,7 @@ #include "oops/oop.inline.hpp" #include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/orderAccess.inline.hpp" diff --git a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp similarity index 76% rename from src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp rename to src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp index eed1c456c01..43de961a1f6 100644 --- a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp @@ -24,12 +24,12 @@ #include "precompiled.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "utilities/globalDefinitions.hpp" -Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1RSetRegionEntries=0 means will be set ergonomically. // Minimum value is 1. @@ -38,14 +38,14 @@ Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { "G1RSetRegionEntries (" INTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. // Minimum value is 1. @@ -54,14 +54,14 @@ Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; // Default value of G1HeapRegionSize=0 means will be set ergonomically. if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { @@ -69,53 +69,53 @@ Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { "G1HeapRegionSize (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic heap region minimum size\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; if (value > G1MaxNewSizePercent) { CommandLineError::print(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n", value, G1MaxNewSizePercent); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { - if (!UseG1GC) return Flag::SUCCESS; +JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return JVMFlag::SUCCESS; if (value < G1NewSizePercent) { CommandLineError::print(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n", value, G1NewSizePercent); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { +JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { CommandLineError::print(verbose, "MaxGCPauseMillis (" UINTX_FORMAT ") must be " "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n", value, GCPauseIntervalMillis); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { +JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { if (UseG1GC) { if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { if (value < 1) { @@ -123,14 +123,14 @@ Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than or equal to 1\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) { CommandLineError::print(verbose, "GCPauseIntervalMillis cannot be set " "without setting MaxGCPauseMillis\n"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value <= MaxGCPauseMillis) { @@ -138,15 +138,15 @@ Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) { "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n", value, MaxGCPauseMillis); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { +JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { #ifdef _LP64 // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length // when the value to be assigned exceeds uint range. @@ -156,10 +156,10 @@ Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) { CommandLineError::print(verbose, "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif // _LP64 - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } size_t MaxSizeForHeapAlignmentG1() { diff --git a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp similarity index 67% rename from src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp rename to src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp index a81bd4254e1..29a98038296 100644 --- a/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.hpp @@ -29,17 +29,17 @@ #include "utilities/globalDefinitions.hpp" // G1 Flag Constraints -Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); -Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); -Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); -Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); -Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); +JVMFlag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); +JVMFlag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); +JVMFlag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); +JVMFlag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); // G1 Subconstraints -Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose); -Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose); -Flag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose); -Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose); +JVMFlag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose); +JVMFlag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose); +JVMFlag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose); +JVMFlag::Error NewSizeConstraintFuncG1(size_t value, bool verbose); size_t MaxSizeForHeapAlignmentG1(); diff --git a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp similarity index 82% rename from src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp rename to src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp index 54742369c1a..ab95428b26e 100644 --- a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp +++ b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.cpp @@ -23,11 +23,11 @@ */ #include "precompiled.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "utilities/globalDefinitions.hpp" -Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { +JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. // So can't exceed with "max_jint" @@ -36,24 +36,24 @@ Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) { "ParallelGCThreads (" UINT32_FORMAT ") must be " "less than or equal to " UINT32_FORMAT " for Parallel GC\n", value, max_jint); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { +JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // InitialTenuringThreshold is only used for ParallelGC. if (UseParallelGC && (value > MaxTenuringThreshold)) { CommandLineError::print(verbose, "InitialTenuringThreshold (" UINTX_FORMAT ") must be " "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", value, MaxTenuringThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { +JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) { // As only ParallelGC uses InitialTenuringThreshold, // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. if (UseParallelGC && (value < InitialTenuringThreshold)) { @@ -61,8 +61,8 @@ Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose "MaxTenuringThreshold (" UINTX_FORMAT ") must be " "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", value, InitialTenuringThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp similarity index 84% rename from src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp rename to src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp index caa82209035..b945d8ea3bf 100644 --- a/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp +++ b/src/hotspot/share/gc/parallel/jvmFlagConstraintsParallel.hpp @@ -29,8 +29,8 @@ #include "utilities/globalDefinitions.hpp" // Parallel Subconstraints -Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose); -Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); -Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); +JVMFlag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose); +JVMFlag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); +JVMFlag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose); #endif // SHARE_GC_PARALLEL_COMMANDLINEFLAGCONSTRAINTSPARALLEL_HPP diff --git a/src/hotspot/share/gc/parallel/psMarkSweep.cpp b/src/hotspot/share/gc/parallel/psMarkSweep.cpp index b7f2770f5f3..48456123347 100644 --- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp +++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp @@ -51,6 +51,7 @@ #include "logging/log.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/vmThread.hpp" diff --git a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp deleted file mode 100644 index dcfaf529c97..00000000000 --- a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP -#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc/cms/commandLineFlagConstraintsCMS.hpp" -#include "gc/g1/commandLineFlagConstraintsG1.hpp" -#include "gc/parallel/commandLineFlagConstraintsParallel.hpp" -#endif - -/* - * Here we have GC arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); -Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); -Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); -Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); -Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); -Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); - -Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); -Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); -Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); -Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); -Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); -Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); -Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose); -Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); -Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); -Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); -Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); - -// Internal -Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); - -#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index 30754c90a83..b14db143052 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -53,6 +53,7 @@ #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp similarity index 71% rename from src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp rename to src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 14491c91645..4378da92890 100644 --- a/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -25,11 +25,11 @@ #include "precompiled.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectorPolicy.hpp" -#include "gc/shared/commandLineFlagConstraintsGC.hpp" +#include "gc/shared/jvmFlagConstraintsGC.hpp" #include "gc/shared/plab.hpp" #include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/thread.inline.hpp" @@ -37,9 +37,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS -#include "gc/cms/commandLineFlagConstraintsCMS.hpp" -#include "gc/g1/commandLineFlagConstraintsG1.hpp" -#include "gc/parallel/commandLineFlagConstraintsParallel.hpp" +#include "gc/cms/jvmFlagConstraintsCMS.hpp" +#include "gc/g1/jvmFlagConstraintsG1.hpp" +#include "gc/parallel/jvmFlagConstraintsParallel.hpp" #endif #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -57,17 +57,17 @@ // the flag has been set by the user and so should be checked. // As ParallelGCThreads differs among GC modes, we need constraint function. -Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; #if INCLUDE_ALL_GCS status = ParallelGCThreadsConstraintFuncParallel(value, verbose); - if (status != Flag::SUCCESS) { + if (status != JVMFlag::SUCCESS) { return status; } status = ParallelGCThreadsConstraintFuncCMS(value, verbose); - if (status != Flag::SUCCESS) { + if (status != JVMFlag::SUCCESS) { return status; } #endif @@ -77,7 +77,7 @@ Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { // As ConcGCThreads should be smaller than ParallelGCThreads, // we need constraint function. -Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { +JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { #if INCLUDE_ALL_GCS // CMS and G1 GCs use ConcGCThreads. if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) { @@ -85,53 +85,53 @@ Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { "ConcGCThreads (" UINT32_FORMAT ") must be " "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n", value, ParallelGCThreads); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { +static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n", name, value, PLAB::min_size()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif // INCLUDE_ALL_GCS - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { +JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n", name, value, PLAB::max_size()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif // INCLUDE_ALL_GCS - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - Flag::Error status = MinPLABSizeBounds(name, value, verbose); +static JVMFlag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { + JVMFlag::Error status = MinPLABSizeBounds(name, value, verbose); - if (status == Flag::SUCCESS) { + if (status == JVMFlag::SUCCESS) { return MaxPLABSizeBounds(name, value, verbose); } return status; } -Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); } -Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { - Flag::Error status = Flag::SUCCESS; +JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { @@ -143,98 +143,98 @@ Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { return status; } -Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { CommandLineError::print(verbose, "MinHeapFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n", value, MaxHeapFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinHeapFreeRatio) { CommandLineError::print(verbose, "MaxHeapFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n", value, MinHeapFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { +static JVMFlag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) { CommandLineError::print(verbose, "Desired lifetime of SoftReferences cannot be expressed correctly. " "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " "(" INTX_FORMAT ") is too large\n", maxHeap, softRef); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { +JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); } -Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { if (value > MarkStackSizeMax) { CommandLineError::print(verbose, "MarkStackSize (" SIZE_FORMAT ") must be " "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n", value, MarkStackSizeMax); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { CommandLineError::print(verbose, "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n", value, MaxMetaspaceFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value < MinMetaspaceFreeRatio) { CommandLineError::print(verbose, "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be " "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n", value, MinMetaspaceFreeRatio); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif @@ -247,59 +247,59 @@ Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { "AlwaysTenure=%s\n", NeverTenure ? "true" : "false", AlwaysTenure ? "true" : "false"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { size_t aligned_max = align_down(max_uintx/2, Metaspace::reserve_alignment_words()); if (value > aligned_max) { CommandLineError::print(verbose, "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", value, aligned_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } // To avoid an overflow by 'align_up(value, alignment)'. -static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { +static JVMFlag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) { size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1)); if (value > aligned_max) { CommandLineError::print(verbose, "%s (" SIZE_FORMAT ") must be " "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", name, value, aligned_max); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { +static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { size_t heap_alignment; #if INCLUDE_ALL_GCS @@ -315,20 +315,20 @@ static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool return MaxSizeForAlignment(name, value, heap_alignment, verbose); } -Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); } -Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { - Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); +JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { + JVMFlag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); - if (status == Flag::SUCCESS) { + if (status == JVMFlag::SUCCESS) { status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); } return status; } -Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value. // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx. if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) { @@ -336,43 +336,43 @@ Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) { "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. " "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n", value, MaxHeapSize, max_uintx); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose); } -Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose) { #if INCLUDE_ALL_GCS - Flag::Error status = NewSizeConstraintFuncG1(value, verbose); - if (status != Flag::SUCCESS) { + JVMFlag::Error status = NewSizeConstraintFuncG1(value, verbose); + if (status != JVMFlag::SUCCESS) { return status; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { // At least, alignment reserve area is needed. if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { CommandLineError::print(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { CommandLineError::print(verbose, "MinTLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n", value, ThreadLocalAllocBuffer::max_size() * HeapWordSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { // Skip for default value of zero which means set ergonomically. if (FLAG_IS_CMDLINE(TLABSize)) { if (value < MinTLABSize) { @@ -380,22 +380,22 @@ Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { "TLABSize (" SIZE_FORMAT ") must be " "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n", value, MinTLABSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { CommandLineError::print(verbose, "TLABSize (" SIZE_FORMAT ") must be " "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } // We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(), // so AfterMemoryInit type is enough to check. -Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { if (UseTLAB) { size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit(); @@ -405,13 +405,13 @@ Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) { "TLABWasteIncrement (" UINTX_FORMAT ") must be " "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n", value, (max_uintx - refill_waste_limit)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { if (FLAG_IS_CMDLINE(SurvivorRatio) && (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) { CommandLineError::print(verbose, @@ -419,52 +419,52 @@ Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", value, (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment())); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value > MaxMetaspaceSize) { CommandLineError::print(verbose, "MetaspaceSize (" SIZE_FORMAT ") must be " "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n", value, MaxMetaspaceSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { +JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { if (value < MetaspaceSize) { CommandLineError::print(verbose, "MaxMetaspaceSize (" SIZE_FORMAT ") must be " "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n", value, MaxMetaspaceSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { +JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (value != 0) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (value < ObjectAlignmentInBytes) { CommandLineError::print(verbose, "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", value, ObjectAlignmentInBytes); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp new file mode 100644 index 00000000000..b03409c44a3 --- /dev/null +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP +#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc/cms/jvmFlagConstraintsCMS.hpp" +#include "gc/g1/jvmFlagConstraintsG1.hpp" +#include "gc/parallel/jvmFlagConstraintsParallel.hpp" +#endif + +/* + * Here we have GC arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); +JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); +JVMFlag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); +JVMFlag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); +JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); +JVMFlag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose); +JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error TLABSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose); +JVMFlag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); +JVMFlag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); +JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); + +// Internal +JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose); + +#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 2bc78f5322f..905bab617ca 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -37,6 +37,7 @@ #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/jvmciCodeInstaller.hpp" #include "jvmci/jvmciRuntime.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" @@ -125,7 +126,7 @@ C2V_VMENTRY(jobject, getFlagValue, (JNIEnv *, jobject c2vm, jobject name_handle) } ResourceMark rm; const char* cstring = java_lang_String::as_utf8_string(name()); - Flag* flag = Flag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); + JVMFlag* flag = JVMFlag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); if (flag == NULL) { return c2vm; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 5318b618110..6d9e1d0c4ea 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -29,6 +29,7 @@ #include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/vmStructs_jvmci.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/resourceHash.hpp" @@ -378,9 +379,9 @@ jobjectArray readConfiguration0(JNIEnv *env, TRAPS) { #define COUNT_FLAG(ignore) +1 #ifdef ASSERT #define CHECK_FLAG(type, name) { \ - Flag* flag = Flag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \ + JVMFlag* flag = JVMFlag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \ assert(flag != NULL, "No such flag named " #name); \ - assert(flag->is_##type(), "Flag " #name " is not of type " #type); \ + assert(flag->is_##type(), "JVMFlag " #name " is not of type " #type); \ } #else #define CHECK_FLAG(type, name) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 605e203b0fe..95d0abfb762 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -35,6 +35,7 @@ #include "oops/oop.hpp" #include "oops/oopHandle.hpp" #include "oops/objArrayKlass.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/thread.hpp" @@ -146,16 +147,16 @@ nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ \ - nonstatic_field(ExceptionTableElement, start_pc, u2) \ - nonstatic_field(ExceptionTableElement, end_pc, u2) \ - nonstatic_field(ExceptionTableElement, handler_pc, u2) \ - nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ + nonstatic_field(ExceptionTableElement, start_pc, u2) \ + nonstatic_field(ExceptionTableElement, end_pc, u2) \ + nonstatic_field(ExceptionTableElement, handler_pc, u2) \ + nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ \ - nonstatic_field(Flag, _type, const char*) \ - nonstatic_field(Flag, _name, const char*) \ - unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) \ - nonstatic_field(Flag, _flags, Flag::Flags) \ - static_field(Flag, flags, Flag*) \ + nonstatic_field(JVMFlag, _type, const char*) \ + nonstatic_field(JVMFlag, _name, const char*) \ + unchecked_nonstatic_field(JVMFlag, _addr, sizeof(void*)) \ + nonstatic_field(JVMFlag, _flags, JVMFlag::Flags) \ + static_field(JVMFlag, flags, JVMFlag*) \ \ nonstatic_field(InstanceKlass, _fields, Array*) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ @@ -345,8 +346,8 @@ declare_toplevel_type(BasicLock) \ declare_toplevel_type(CompilerToVM) \ declare_toplevel_type(ExceptionTableElement) \ - declare_toplevel_type(Flag) \ - declare_toplevel_type(Flag*) \ + declare_toplevel_type(JVMFlag) \ + declare_toplevel_type(JVMFlag*) \ declare_toplevel_type(InvocationCounter) \ declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(LocalVariableTableElement) \ diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 66da16fabe5..a35b1b6a4fd 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -63,7 +63,8 @@ #include "prims/resolvedMethodTable.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" +#include "runtime/flags/flagSetting.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" @@ -701,7 +702,7 @@ jint universe_init() { AOTLoader::universe_init(); // Checks 'AfterMemoryInit' constraints. - if (!CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterMemoryInit)) { + if (!JVMFlagConstraintList::check_constraints(JVMFlagConstraint::AfterMemoryInit)) { return JNI_EINVAL; } diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index 40d31912de6..a6bcef24b85 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -38,6 +38,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/copy.hpp" diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index 79753638f77..093c344cce0 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -101,6 +101,7 @@ # include "gc/shared/genCollectedHeap.hpp" # include "gc/shared/generation.hpp" # include "gc/shared/generationCounters.hpp" +# include "gc/shared/jvmFlagConstraintsGC.hpp" # include "gc/shared/modRefBarrierSet.hpp" # include "gc/shared/referencePolicy.hpp" # include "gc/shared/referenceProcessor.hpp" @@ -163,6 +164,13 @@ # include "runtime/extendedPC.hpp" # include "runtime/fieldDescriptor.hpp" # include "runtime/fieldType.hpp" +# include "runtime/flags/flagSetting.hpp" +# include "runtime/flags/jvmFlag.hpp" +# include "runtime/flags/jvmFlagConstraintList.hpp" +# include "runtime/flags/jvmFlagConstraintsCompiler.hpp" +# include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +# include "runtime/flags/jvmFlagRangeList.hpp" +# include "runtime/flags/jvmFlagWriteableList.hpp" # include "runtime/frame.hpp" # include "runtime/frame.inline.hpp" # include "runtime/globals.hpp" @@ -292,6 +300,7 @@ # include "gc/cms/concurrentMarkSweepGeneration.hpp" # include "gc/cms/freeChunk.hpp" # include "gc/cms/gSpaceCounters.hpp" +# include "gc/cms/jvmFlagConstraintsCMS.hpp" # include "gc/cms/parOopClosures.hpp" # include "gc/cms/promotionInfo.hpp" # include "gc/cms/yieldingWorkgroup.hpp" @@ -299,10 +308,12 @@ # include "gc/g1/g1BlockOffsetTable.hpp" # include "gc/g1/g1OopClosures.hpp" # include "gc/g1/g1_globals.hpp" +# include "gc/g1/jvmFlagConstraintsG1.hpp" # include "gc/g1/ptrQueue.hpp" # include "gc/g1/satbMarkQueue.hpp" # include "gc/parallel/gcAdaptivePolicyCounters.hpp" # include "gc/parallel/immutableSpace.hpp" +# include "gc/parallel/jvmFlagConstraintsParallel.hpp" # include "gc/parallel/mutableSpace.hpp" # include "gc/parallel/objectStartArray.hpp" # include "gc/parallel/parMarkBitMap.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 6ff8b83e338..f87099149c5 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -53,6 +53,7 @@ #include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -971,29 +972,29 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) WB_END template -static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAt)(const char*, T*, bool, bool)) { +static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, JVMFlag::Error (*TAt)(const char*, T*, bool, bool)) { if (name == NULL) { return false; } ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); - Flag::Error result = (*TAt)(flag_name, value, true, true); + JVMFlag::Error result = (*TAt)(flag_name, value, true, true); env->ReleaseStringUTFChars(name, flag_name); - return (result == Flag::SUCCESS); + return (result == JVMFlag::SUCCESS); } template -static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAtPut)(const char*, T*, Flag::Flags)) { +static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, JVMFlag::Error (*TAtPut)(const char*, T*, JVMFlag::Flags)) { if (name == NULL) { return false; } ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); - Flag::Error result = (*TAtPut)(flag_name, value, Flag::INTERNAL); + JVMFlag::Error result = (*TAtPut)(flag_name, value, JVMFlag::INTERNAL); env->ReleaseStringUTFChars(name, flag_name); - return (result == Flag::SUCCESS); + return (result == JVMFlag::SUCCESS); } template @@ -1026,28 +1027,28 @@ static jobject doubleBox(JavaThread* thread, JNIEnv* env, jdouble value) { return box(thread, env, vmSymbols::java_lang_Double(), vmSymbols::Double_valueOf_signature(), value); } -static Flag* getVMFlag(JavaThread* thread, JNIEnv* env, jstring name) { +static JVMFlag* getVMFlag(JavaThread* thread, JNIEnv* env, jstring name) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, NULL); - Flag* result = Flag::find_flag(flag_name, strlen(flag_name), true, true); + JVMFlag* result = JVMFlag::find_flag(flag_name, strlen(flag_name), true, true); env->ReleaseStringUTFChars(name, flag_name); return result; } WB_ENTRY(jboolean, WB_IsConstantVMFlag(JNIEnv* env, jobject o, jstring name)) - Flag* flag = getVMFlag(thread, env, name); + JVMFlag* flag = getVMFlag(thread, env, name); return (flag != NULL) && flag->is_constant_in_binary(); WB_END WB_ENTRY(jboolean, WB_IsLockedVMFlag(JNIEnv* env, jobject o, jstring name)) - Flag* flag = getVMFlag(thread, env, name); + JVMFlag* flag = getVMFlag(thread, env, name); return (flag != NULL) && !(flag->is_unlocked() || flag->is_unlocker()); WB_END WB_ENTRY(jobject, WB_GetBooleanVMFlag(JNIEnv* env, jobject o, jstring name)) bool result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::boolAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::boolAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return booleanBox(thread, env, result); } @@ -1056,7 +1057,7 @@ WB_END WB_ENTRY(jobject, WB_GetIntVMFlag(JNIEnv* env, jobject o, jstring name)) int result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::intAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::intAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1065,7 +1066,7 @@ WB_END WB_ENTRY(jobject, WB_GetUintVMFlag(JNIEnv* env, jobject o, jstring name)) uint result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uintAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::uintAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1074,7 +1075,7 @@ WB_END WB_ENTRY(jobject, WB_GetIntxVMFlag(JNIEnv* env, jobject o, jstring name)) intx result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::intxAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::intxAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1083,7 +1084,7 @@ WB_END WB_ENTRY(jobject, WB_GetUintxVMFlag(JNIEnv* env, jobject o, jstring name)) uintx result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uintxAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::uintxAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1092,7 +1093,7 @@ WB_END WB_ENTRY(jobject, WB_GetUint64VMFlag(JNIEnv* env, jobject o, jstring name)) uint64_t result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::uint64_tAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1101,7 +1102,7 @@ WB_END WB_ENTRY(jobject, WB_GetSizeTVMFlag(JNIEnv* env, jobject o, jstring name)) uintx result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::size_tAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return longBox(thread, env, result); } @@ -1110,7 +1111,7 @@ WB_END WB_ENTRY(jobject, WB_GetDoubleVMFlag(JNIEnv* env, jobject o, jstring name)) double result; - if (GetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAt)) { + if (GetVMFlag (thread, env, name, &result, &JVMFlag::doubleAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI return doubleBox(thread, env, result); } @@ -1119,7 +1120,7 @@ WB_END WB_ENTRY(jstring, WB_GetStringVMFlag(JNIEnv* env, jobject o, jstring name)) ccstr ccstrResult; - if (GetVMFlag (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAt)) { + if (GetVMFlag (thread, env, name, &ccstrResult, &JVMFlag::ccstrAt)) { ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI jstring result = env->NewStringUTF(ccstrResult); CHECK_JNI_EXCEPTION_(env, NULL); @@ -1130,42 +1131,42 @@ WB_END WB_ENTRY(void, WB_SetBooleanVMFlag(JNIEnv* env, jobject o, jstring name, jboolean value)) bool result = value == JNI_TRUE ? true : false; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::boolAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::boolAtPut); WB_END WB_ENTRY(void, WB_SetIntVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) int result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::intAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::intAtPut); WB_END WB_ENTRY(void, WB_SetUintVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uint result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::uintAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::uintAtPut); WB_END WB_ENTRY(void, WB_SetIntxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) intx result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::intxAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::intxAtPut); WB_END WB_ENTRY(void, WB_SetUintxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uintx result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::uintxAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::uintxAtPut); WB_END WB_ENTRY(void, WB_SetUint64VMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) uint64_t result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::uint64_tAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::uint64_tAtPut); WB_END WB_ENTRY(void, WB_SetSizeTVMFlag(JNIEnv* env, jobject o, jstring name, jlong value)) size_t result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::size_tAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::size_tAtPut); WB_END WB_ENTRY(void, WB_SetDoubleVMFlag(JNIEnv* env, jobject o, jstring name, jdouble value)) double result = value; - SetVMFlag (thread, env, name, &result, &CommandLineFlags::doubleAtPut); + SetVMFlag (thread, env, name, &result, &JVMFlag::doubleAtPut); WB_END WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring value)) @@ -1182,7 +1183,7 @@ WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring bool needFree; { ThreadInVMfromNative ttvfn(thread); // back to VM - needFree = SetVMFlag (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAtPut); + needFree = SetVMFlag (thread, env, name, &ccstrResult, &JVMFlag::ccstrAtPut); } if (value != NULL) { env->ReleaseStringUTFChars(value, ccstrValue); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 874c86a018d..1e49fe1d35d 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -42,10 +42,10 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/arguments_ext.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "runtime/os.inline.hpp" @@ -739,7 +739,7 @@ static bool verify_special_jvm_flags() { // if flag has become obsolete it should not have a "globals" flag defined anymore. if (!version_less_than(JDK_Version::current(), flag.obsolete_in)) { - if (Flag::find_flag(flag.name) != NULL) { + if (JVMFlag::find_flag(flag.name) != NULL) { // Temporarily disable the warning: 8196739 // warning("Global variable for obsolete special flag entry \"%s\" should be removed", flag.name); } @@ -749,7 +749,7 @@ static bool verify_special_jvm_flags() { if (!flag.expired_in.is_undefined()) { // if flag has become expired it should not have a "globals" flag defined anymore. if (!version_less_than(JDK_Version::current(), flag.expired_in)) { - if (Flag::find_flag(flag.name) != NULL) { + if (JVMFlag::find_flag(flag.name) != NULL) { // Temporarily disable the warning: 8196739 // warning("Global variable for expired flag entry \"%s\" should be removed", flag.name); } @@ -833,15 +833,15 @@ void Arguments::describe_range_error(ArgsRange errcode) { } } -static bool set_bool_flag(const char* name, bool value, Flag::Flags origin) { - if (CommandLineFlags::boolAtPut(name, &value, origin) == Flag::SUCCESS) { +static bool set_bool_flag(const char* name, bool value, JVMFlag::Flags origin) { + if (JVMFlag::boolAtPut(name, &value, origin) == JVMFlag::SUCCESS) { return true; } else { return false; } } -static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origin) { +static bool set_fp_numeric_flag(const char* name, char* value, JVMFlag::Flags origin) { char* end; errno = 0; double v = strtod(value, &end); @@ -849,18 +849,18 @@ static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origi return false; } - if (CommandLineFlags::doubleAtPut(name, &v, origin) == Flag::SUCCESS) { + if (JVMFlag::doubleAtPut(name, &v, origin) == JVMFlag::SUCCESS) { return true; } return false; } -static bool set_numeric_flag(const char* name, char* value, Flag::Flags origin) { +static bool set_numeric_flag(const char* name, char* value, JVMFlag::Flags origin) { julong v; int int_v; intx intx_v; bool is_neg = false; - Flag* result = Flag::find_flag(name, strlen(name)); + JVMFlag* result = JVMFlag::find_flag(name, strlen(name)); if (result == NULL) { return false; @@ -882,43 +882,43 @@ static bool set_numeric_flag(const char* name, char* value, Flag::Flags origin) if (is_neg) { int_v = -int_v; } - return CommandLineFlags::intAtPut(result, &int_v, origin) == Flag::SUCCESS; + return JVMFlag::intAtPut(result, &int_v, origin) == JVMFlag::SUCCESS; } else if (result->is_uint()) { uint uint_v = (uint) v; - return CommandLineFlags::uintAtPut(result, &uint_v, origin) == Flag::SUCCESS; + return JVMFlag::uintAtPut(result, &uint_v, origin) == JVMFlag::SUCCESS; } else if (result->is_intx()) { intx_v = (intx) v; if (is_neg) { intx_v = -intx_v; } - return CommandLineFlags::intxAtPut(result, &intx_v, origin) == Flag::SUCCESS; + return JVMFlag::intxAtPut(result, &intx_v, origin) == JVMFlag::SUCCESS; } else if (result->is_uintx()) { uintx uintx_v = (uintx) v; - return CommandLineFlags::uintxAtPut(result, &uintx_v, origin) == Flag::SUCCESS; + return JVMFlag::uintxAtPut(result, &uintx_v, origin) == JVMFlag::SUCCESS; } else if (result->is_uint64_t()) { uint64_t uint64_t_v = (uint64_t) v; - return CommandLineFlags::uint64_tAtPut(result, &uint64_t_v, origin) == Flag::SUCCESS; + return JVMFlag::uint64_tAtPut(result, &uint64_t_v, origin) == JVMFlag::SUCCESS; } else if (result->is_size_t()) { size_t size_t_v = (size_t) v; - return CommandLineFlags::size_tAtPut(result, &size_t_v, origin) == Flag::SUCCESS; + return JVMFlag::size_tAtPut(result, &size_t_v, origin) == JVMFlag::SUCCESS; } else if (result->is_double()) { double double_v = (double) v; - return CommandLineFlags::doubleAtPut(result, &double_v, origin) == Flag::SUCCESS; + return JVMFlag::doubleAtPut(result, &double_v, origin) == JVMFlag::SUCCESS; } else { return false; } } -static bool set_string_flag(const char* name, const char* value, Flag::Flags origin) { - if (CommandLineFlags::ccstrAtPut(name, &value, origin) != Flag::SUCCESS) return false; - // Contract: CommandLineFlags always returns a pointer that needs freeing. +static bool set_string_flag(const char* name, const char* value, JVMFlag::Flags origin) { + if (JVMFlag::ccstrAtPut(name, &value, origin) != JVMFlag::SUCCESS) return false; + // Contract: JVMFlag always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); return true; } -static bool append_to_string_flag(const char* name, const char* new_value, Flag::Flags origin) { +static bool append_to_string_flag(const char* name, const char* new_value, JVMFlag::Flags origin) { const char* old_value = ""; - if (CommandLineFlags::ccstrAt(name, &old_value) != Flag::SUCCESS) return false; + if (JVMFlag::ccstrAt(name, &old_value) != JVMFlag::SUCCESS) return false; size_t old_len = old_value != NULL ? strlen(old_value) : 0; size_t new_len = strlen(new_value); const char* value; @@ -935,11 +935,11 @@ static bool append_to_string_flag(const char* name, const char* new_value, Flag: value = buf; free_this_too = buf; } - (void) CommandLineFlags::ccstrAtPut(name, &value, origin); - // CommandLineFlags always returns a pointer that needs freeing. + (void) JVMFlag::ccstrAtPut(name, &value, origin); + // JVMFlag always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); if (free_this_too != NULL) { - // CommandLineFlags made its own copy, so I must delete my own temp. buffer. + // JVMFlag made its own copy, so I must delete my own temp. buffer. FREE_C_HEAP_ARRAY(char, free_this_too); } return true; @@ -1010,7 +1010,7 @@ AliasedLoggingFlag Arguments::catch_logging_aliases(const char* name, bool on){ return a; } -bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { +bool Arguments::parse_argument(const char* arg, JVMFlag::Flags origin) { // range of acceptable characters spelled out for portability reasons #define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]" @@ -1048,7 +1048,7 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { char punct; if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "%c", name, &punct) == 2 && punct == '=') { const char* value = strchr(arg, '=') + 1; - Flag* flag; + JVMFlag* flag; // this scanf pattern matches both strings (handled here) and numbers (handled later)) AliasedLoggingFlag alf = catch_logging_aliases(name, true); @@ -1060,7 +1060,7 @@ bool Arguments::parse_argument(const char* arg, Flag::Flags origin) { if (real_name == NULL) { return false; } - flag = Flag::find_flag(real_name); + flag = JVMFlag::find_flag(real_name); if (flag != NULL && flag->is_ccstr()) { if (flag->ccstr_accumulates()) { return append_to_string_flag(real_name, value, origin); @@ -1221,7 +1221,7 @@ void Arguments::print_jvm_args_on(outputStream* st) { bool Arguments::process_argument(const char* arg, jboolean ignore_unrecognized, - Flag::Flags origin) { + JVMFlag::Flags origin) { JDK_Version since = JDK_Version(); if (parse_argument(arg, origin)) { @@ -1266,10 +1266,10 @@ bool Arguments::process_argument(const char* arg, // For locked flags, report a custom error message if available. // Otherwise, report the standard unrecognized VM option. - Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true, true); + JVMFlag* found_flag = JVMFlag::find_flag((const char*)argname, arg_len, true, true); if (found_flag != NULL) { char locked_message_buf[BUFLEN]; - Flag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN); + JVMFlag::MsgType msg_type = found_flag->get_locked_message(locked_message_buf, BUFLEN); if (strlen(locked_message_buf) == 0) { if (found_flag->is_bool() && !has_plus_minus) { jio_fprintf(defaultStream::error_stream(), @@ -1283,8 +1283,8 @@ bool Arguments::process_argument(const char* arg, } } else { #ifdef PRODUCT - bool mismatched = ((msg_type == Flag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) || - (msg_type == Flag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD)); + bool mismatched = ((msg_type == JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD) || + (msg_type == JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD)); if (ignore_unrecognized && mismatched) { return true; } @@ -1297,7 +1297,7 @@ bool Arguments::process_argument(const char* arg, } jio_fprintf(defaultStream::error_stream(), "Unrecognized VM option '%s'\n", argname); - Flag* fuzzy_matched = Flag::fuzzy_match((const char*)argname, arg_len, true); + JVMFlag* fuzzy_matched = JVMFlag::fuzzy_match((const char*)argname, arg_len, true); if (fuzzy_matched != NULL) { jio_fprintf(defaultStream::error_stream(), "Did you mean '%s%s%s'? ", @@ -1350,7 +1350,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, // this allows a way to include spaces in string-valued options token[pos] = '\0'; logOption(token); - result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); build_jvm_flags(token); pos = 0; in_white_space = true; @@ -1368,7 +1368,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } if (pos > 0) { token[pos] = '\0'; - result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); build_jvm_flags(token); } fclose(stream); @@ -1991,10 +1991,10 @@ jint Arguments::set_aggressive_heap_flags() { initHeapSize = limit_by_allocatable_memory(initHeapSize); if (FLAG_IS_DEFAULT(MaxHeapSize)) { - if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Currently the minimum size and the initial heap sizes are the same. @@ -2003,10 +2003,10 @@ jint Arguments::set_aggressive_heap_flags() { if (FLAG_IS_DEFAULT(NewSize)) { // Make the young generation 3/8ths of the total heap. if (FLAG_SET_CMDLINE(size_t, NewSize, - ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != Flag::SUCCESS) { + ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2016,20 +2016,20 @@ jint Arguments::set_aggressive_heap_flags() { #endif // Increase some data structure sizes for efficiency - if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, TLABSize, 256 * K) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // See the OldPLABSize comment below, but replace 'after promotion' // with 'after copying'. YoungPLABSize is the size of the survivor // space per-gc-thread buffers. The default is 4kw. - if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != Flag::SUCCESS) { // Note: this is in words + if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256 * K) != JVMFlag::SUCCESS) { // Note: this is in words return JNI_EINVAL; } @@ -2046,29 +2046,29 @@ jint Arguments::set_aggressive_heap_flags() { // locality. A minor effect may be that larger PLABs reduce the // number of PLAB allocation events during gc. The value of 8kw // was arrived at by experimenting with specjbb. - if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != Flag::SUCCESS) { // Note: this is in words + if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8 * K) != JVMFlag::SUCCESS) { // Note: this is in words return JNI_EINVAL; } // Enable parallel GC and adaptive generation sizing - if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Encourage steady state memory management - if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // This appears to improve mutator locality - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Get around early Solaris scheduling bug // (affinity vs other jobs on system) // but disallow DR and offlining (5008695). - if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } @@ -2409,20 +2409,20 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, // Parse args structure generated from JAVA_TOOL_OPTIONS environment // variable (if present). - jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); + jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Parse args structure generated from the command line flags. - result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, Flag::COMMAND_LINE); + result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, JVMFlag::COMMAND_LINE); if (result != JNI_OK) { return result; } // Parse args structure generated from the _JAVA_OPTIONS environment // variable (if present) (mimics classic VM) - result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); + result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); if (result != JNI_OK) { return result; } @@ -2566,7 +2566,7 @@ jint Arguments::parse_xss(const JavaVMOption* option, const char* tail, intx* ou return JNI_OK; } -jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin) { +jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin) { // For match_option to return remaining or value part of option string const char* tail; @@ -2599,7 +2599,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m } else if (!strcmp(tail, ":gc")) { LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc)); } else if (!strcmp(tail, ":jni")) { - if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2736,24 +2736,24 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_enable_preview(); // -Xnoclassgc } else if (match_option(option, "-Xnoclassgc")) { - if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xconcgc } else if (match_option(option, "-Xconcgc")) { - if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } handle_extra_cms_flags("-Xconcgc uses UseConcMarkSweepGC"); // -Xnoconcgc } else if (match_option(option, "-Xnoconcgc")) { - if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } handle_extra_cms_flags("-Xnoconcgc uses UseConcMarkSweepGC"); // -Xbatch } else if (match_option(option, "-Xbatch")) { - if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xmn for compatibility with other JVM vendors @@ -2766,10 +2766,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m describe_range_error(errcode); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xms @@ -2786,7 +2786,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_min_heap_size((size_t)long_initial_heap_size); // Currently the minimum size and the initial heap sizes are the same. // Can be overridden with -XX:InitialHeapSize. - if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xmx @@ -2799,7 +2799,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m describe_range_error(errcode); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // Xmaxf @@ -2812,7 +2812,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m option->optionString); return JNI_EINVAL; } else { - if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2826,7 +2826,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m option->optionString); return JNI_EINVAL; } else { - if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } @@ -2837,7 +2837,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m if (err != JNI_OK) { return err; } - if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(intx, ThreadStackSize, value) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-Xmaxjitcodesize", &tail) || @@ -2850,7 +2850,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m "Invalid maximum code cache size: %s.\n", option->optionString); return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -green @@ -2864,7 +2864,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xrs } else if (match_option(option, "-Xrs")) { // Classic/EVM option, new functionality - if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xprof @@ -2875,17 +2875,17 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m warning("Ignoring option %s; support was removed in %s", option->optionString, version); // -Xconcurrentio } else if (match_option(option, "-Xconcurrentio")) { - if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } SafepointSynchronize::set_defer_thr_suspend_loop_count(); - if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != Flag::SUCCESS) { // 20Kb per thread added to new generation + if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != JVMFlag::SUCCESS) { // 20Kb per thread added to new generation return JNI_EINVAL; } @@ -2897,7 +2897,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m #ifndef PRODUCT // -Xprintflags } else if (match_option(option, "-Xprintflags")) { - CommandLineFlags::printFlags(tty, false); + JVMFlag::printFlags(tty, false); vm_exit(0); #endif // -D @@ -2932,7 +2932,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // Out of the box management support if (match_option(option, "-Dcom.sun.management", &tail)) { #if INCLUDE_MANAGEMENT - if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // management agent in module jdk.management.agent @@ -2957,55 +2957,55 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m set_mode_flags(_comp); // -Xshare:dump } else if (match_option(option, "-Xshare:dump")) { - if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } set_mode_flags(_int); // Prevent compilation, which creates objects // -Xshare:on } else if (match_option(option, "-Xshare:on")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xshare:auto } else if (match_option(option, "-Xshare:auto")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xshare:off } else if (match_option(option, "-Xshare:off")) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // -Xverify } else if (match_option(option, "-Xverify", &tail)) { if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (strcmp(tail, ":remote") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (strcmp(tail, ":none") == 0) { - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (is_bad_option(option, args->ignoreUnrecognized, "verification")) { @@ -3064,23 +3064,23 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure; // and the last option wins. } else if (match_option(option, "-XX:+NeverTenure")) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+AlwaysTenure")) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) { @@ -3091,51 +3091,51 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != JVMFlag::SUCCESS) { return JNI_EINVAL; } if (MaxTenuringThreshold == 0) { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else { - if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } } else if (match_option(option, "-XX:+DisplayVMOutputToStderr")) { - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+DisplayVMOutputToStdout")) { - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } } else if (match_option(option, "-XX:+ExtendedDTraceProbes")) { #if defined(DTRACE_ENABLED) - if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } #else // defined(DTRACE_ENABLED) @@ -3145,11 +3145,11 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m #endif // defined(DTRACE_ENABLED) #ifdef ASSERT } else if (match_option(option, "-XX:+FullGCALot")) { - if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } // disable scavenge before parallel mark-compact - if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } #endif @@ -3178,10 +3178,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xshare:on // -Xlog:class+path=info if (PrintSharedArchiveAndExit) { - if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { + if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) { return JNI_EINVAL; } LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(class, path)); @@ -3856,7 +3856,7 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, continue; } if (match_option(option, "-XX:+PrintFlagsInitial")) { - CommandLineFlags::printFlags(tty, false); + JVMFlag::printFlags(tty, false); vm_exit(0); } if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { @@ -3885,13 +3885,13 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, #ifndef PRODUCT if (match_option(option, "-XX:+PrintFlagsWithComments")) { - CommandLineFlags::printFlags(tty, true); + JVMFlag::printFlags(tty, true); vm_exit(0); } #endif if (match_option(option, "-XX:+UseAppCDS")) { - Flag* flag = Flag::find_flag("SharedArchiveFile", 17, true, true); + JVMFlag* flag = JVMFlag::find_flag("SharedArchiveFile", 17, true, true); if (flag->is_diagnostic()) { flag->clear_diagnostic(); } @@ -3947,9 +3947,9 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { assert(verify_special_jvm_flags(), "deprecated and obsolete flag table inconsistent"); // Initialize ranges, constraints and writeables - CommandLineFlagRangeList::init(); - CommandLineFlagConstraintList::init(); - CommandLineFlagWriteableList::init(); + JVMFlagRangeList::init(); + JVMFlagConstraintList::init(); + JVMFlagWriteableList::init(); // If flag "-XX:Flags=flags-file" is used it will be the first option to be processed. const char* hotspotrc = ".hotspotrc"; @@ -4250,7 +4250,7 @@ jint Arguments::apply_ergo() { #endif // PRODUCT if (PrintCommandLineFlags) { - CommandLineFlags::printSetFlags(tty); + JVMFlag::printSetFlags(tty); } // Apply CPU specific policy for the BiasedLocking diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 83dd78fff81..edf88193673 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -28,6 +28,7 @@ #include "logging/logLevel.hpp" #include "logging/logTag.hpp" #include "memory/allocation.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" @@ -413,8 +414,8 @@ class Arguments : AllStatic { // Argument parsing static void do_pd_flag_adjustments(); - static bool parse_argument(const char* arg, Flag::Flags origin); - static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin); + static bool parse_argument(const char* arg, JVMFlag::Flags origin); + static bool process_argument(const char* arg, jboolean ignore_unrecognized, JVMFlag::Flags origin); static void process_java_launcher_argument(const char*, void*); static void process_java_compiler_argument(const char* arg); static jint parse_options_environment_variable(const char* name, ScopedVMInitArgs* vm_args); @@ -442,7 +443,7 @@ class Arguments : AllStatic { static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin); static jint finalize_vm_init_args(bool patch_mod_javabase); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp deleted file mode 100644 index 6700bb1da4d..00000000000 --- a/src/hotspot/share/runtime/commandLineFlagConstraintList.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP - -#include "runtime/globals.hpp" -#include "utilities/growableArray.hpp" - -/* - * Here we have a mechanism for extracting constraints (as custom functions) for flags, - * which otherwise can not be expressed via simple range check, specified in flag macro tables. - * - * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change. - * - * See runtime "runtime/commandLineFlagConstraintsCompiler.hpp", - * "runtime/commandLineFlagConstraintsGC.hpp" and - * "runtime/commandLineFlagConstraintsRuntime.hpp" for the functions themselves. - */ - -typedef Flag::Error (*CommandLineFlagConstraintFunc_bool)(bool value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_int)(int value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_intx)(intx value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_uint)(uint value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_uintx)(uintx value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(size_t value, bool verbose); -typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(double value, bool verbose); - -class CommandLineFlagConstraint : public CHeapObj { -public: - // During VM initialization, constraint validation will be done order of ConstraintType. - enum ConstraintType { - // Will be validated during argument processing (Arguments::parse_argument). - AtParse = 0, - // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). - AfterErgo = 1, - // Will be validated inside universe_init(), right after Metaspace::global_initialize(). - AfterMemoryInit = 2 - }; - -private: - const char* _name; - ConstraintType _validate_type; - -public: - // the "name" argument must be a string literal - CommandLineFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; - ~CommandLineFlagConstraint() {}; - const char* name() const { return _name; } - ConstraintType type() const { return _validate_type; } - virtual Flag::Error apply(bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; - virtual Flag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }; -}; - -class CommandLineFlagConstraintList : public AllStatic { -private: - static GrowableArray* _constraints; - // Latest constraint validation type. - static CommandLineFlagConstraint::ConstraintType _validating_type; -public: - static void init(); - static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } - static CommandLineFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } - static CommandLineFlagConstraint* find(const char* name); - static CommandLineFlagConstraint* find_if_needs_check(const char* name); - static void add(CommandLineFlagConstraint* constraint) { _constraints->append(constraint); } - // True if 'AfterErgo' or later constraint functions are validated. - static bool validated_after_ergo() { return _validating_type >= CommandLineFlagConstraint::AfterErgo; }; - static bool check_constraints(CommandLineFlagConstraint::ConstraintType type); -}; - -#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp deleted file mode 100644 index b0596e93a19..00000000000 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP - -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" - -/* - * Here we have compiler arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -Flag::Error AliasLevelConstraintFunc(intx value, bool verbose); - -Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose); - -Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); - -Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); - -Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); - -Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose); - -Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); - -Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); - -Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); - -Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); - -Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); - -Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); - -Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); - -Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); - -Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose); - -#ifdef COMPILER2 -Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); - -Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); -#endif - -Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose); - -#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/src/hotspot/share/runtime/flags/flagSetting.hpp b/src/hotspot/share/runtime/flags/flagSetting.hpp new file mode 100644 index 00000000000..f2f629b0fb3 --- /dev/null +++ b/src/hotspot/share/runtime/flags/flagSetting.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP +#define SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP + +#include "memory/allocation.hpp" + +// debug flags control various aspects of the VM and are global accessible + +// use FlagSetting to temporarily change some debug flag +// e.g. FlagSetting fs(DebugThisAndThat, true); +// restored to previous value upon leaving scope +class FlagSetting : public StackObj { + bool val; + bool* flag; +public: + FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; } + ~FlagSetting() { *flag = val; } +}; + +class UIntFlagSetting : public StackObj { + uint val; + uint* flag; +public: + UIntFlagSetting(uint& fl, uint newValue) { flag = &fl; val = fl; fl = newValue; } + ~UIntFlagSetting() { *flag = val; } +}; + +class SizeTFlagSetting : public StackObj { + size_t val; + size_t* flag; +public: + SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } + ~SizeTFlagSetting() { *flag = val; } +}; + +// Helper class for temporarily saving the value of a flag during a scope. +template +class FlagGuard { + unsigned char _value[SIZE]; + void* const _addr; +public: + FlagGuard(void* flag_addr) : _addr(flag_addr) { memcpy(_value, _addr, SIZE); } + ~FlagGuard() { memcpy(_addr, _value, SIZE); } +}; + +#define FLAG_GUARD(f) FlagGuard f ## _guard(&f) + +#endif // SHARE_VM_RUNTIME_FLAGS_FLAGSETTING_HPP diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp new file mode 100644 index 00000000000..b6f6b55f2ea --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -0,0 +1,1506 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/globals_extension.hpp" +#include "trace/tracing.hpp" +#include "utilities/defaultStream.hpp" +#include "utilities/stringUtils.hpp" + +#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 +static char* create_range_str(const char *fmt, ...) { + static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; + static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); + + int size_needed = 0; + do { + va_list args; + va_start(args, fmt); + size_needed = jio_vsnprintf(range_string, string_length, fmt, args); + va_end(args); + + if (size_needed < 0) { + string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; + range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); + guarantee(range_string != NULL, "create_range_str string should not be NULL"); + } + } while (size_needed < 0); + + return range_string; +} + +const char* JVMFlag::get_int_default_range_str() { + return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); +} + +const char* JVMFlag::get_uint_default_range_str() { + return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); +} + +const char* JVMFlag::get_intx_default_range_str() { + return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); +} + +const char* JVMFlag::get_uintx_default_range_str() { + return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); +} + +const char* JVMFlag::get_uint64_t_default_range_str() { + return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); +} + +const char* JVMFlag::get_size_t_default_range_str() { + return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); +} + +const char* JVMFlag::get_double_default_range_str() { + return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); +} + +static bool is_product_build() { +#ifdef PRODUCT + return true; +#else + return false; +#endif +} + +JVMFlag::Error JVMFlag::check_writable(bool changed) { + if (is_constant_in_binary()) { + fatal("flag is constant: %s", _name); + } + + JVMFlag::Error error = JVMFlag::SUCCESS; + if (changed) { + JVMFlagWriteable* writeable = JVMFlagWriteableList::find(_name); + if (writeable) { + if (writeable->is_writeable() == false) { + switch (writeable->type()) + { + case JVMFlagWriteable::Once: + error = JVMFlag::SET_ONLY_ONCE; + jio_fprintf(defaultStream::error_stream(), "Error: %s may not be set more than once\n", _name); + break; + case JVMFlagWriteable::CommandLineOnly: + error = JVMFlag::COMMAND_LINE_ONLY; + jio_fprintf(defaultStream::error_stream(), "Error: %s may be modified only from commad line\n", _name); + break; + default: + ShouldNotReachHere(); + break; + } + } + writeable->mark_once(); + } + } + return error; +} + +bool JVMFlag::is_bool() const { + return strcmp(_type, "bool") == 0; +} + +bool JVMFlag::get_bool() const { + return *((bool*) _addr); +} + +JVMFlag::Error JVMFlag::set_bool(bool value) { + JVMFlag::Error error = check_writable(value!=get_bool()); + if (error == JVMFlag::SUCCESS) { + *((bool*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_int() const { + return strcmp(_type, "int") == 0; +} + +int JVMFlag::get_int() const { + return *((int*) _addr); +} + +JVMFlag::Error JVMFlag::set_int(int value) { + JVMFlag::Error error = check_writable(value!=get_int()); + if (error == JVMFlag::SUCCESS) { + *((int*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_uint() const { + return strcmp(_type, "uint") == 0; +} + +uint JVMFlag::get_uint() const { + return *((uint*) _addr); +} + +JVMFlag::Error JVMFlag::set_uint(uint value) { + JVMFlag::Error error = check_writable(value!=get_uint()); + if (error == JVMFlag::SUCCESS) { + *((uint*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_intx() const { + return strcmp(_type, "intx") == 0; +} + +intx JVMFlag::get_intx() const { + return *((intx*) _addr); +} + +JVMFlag::Error JVMFlag::set_intx(intx value) { + JVMFlag::Error error = check_writable(value!=get_intx()); + if (error == JVMFlag::SUCCESS) { + *((intx*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_uintx() const { + return strcmp(_type, "uintx") == 0; +} + +uintx JVMFlag::get_uintx() const { + return *((uintx*) _addr); +} + +JVMFlag::Error JVMFlag::set_uintx(uintx value) { + JVMFlag::Error error = check_writable(value!=get_uintx()); + if (error == JVMFlag::SUCCESS) { + *((uintx*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_uint64_t() const { + return strcmp(_type, "uint64_t") == 0; +} + +uint64_t JVMFlag::get_uint64_t() const { + return *((uint64_t*) _addr); +} + +JVMFlag::Error JVMFlag::set_uint64_t(uint64_t value) { + JVMFlag::Error error = check_writable(value!=get_uint64_t()); + if (error == JVMFlag::SUCCESS) { + *((uint64_t*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_size_t() const { + return strcmp(_type, "size_t") == 0; +} + +size_t JVMFlag::get_size_t() const { + return *((size_t*) _addr); +} + +JVMFlag::Error JVMFlag::set_size_t(size_t value) { + JVMFlag::Error error = check_writable(value!=get_size_t()); + if (error == JVMFlag::SUCCESS) { + *((size_t*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_double() const { + return strcmp(_type, "double") == 0; +} + +double JVMFlag::get_double() const { + return *((double*) _addr); +} + +JVMFlag::Error JVMFlag::set_double(double value) { + JVMFlag::Error error = check_writable(value!=get_double()); + if (error == JVMFlag::SUCCESS) { + *((double*) _addr) = value; + } + return error; +} + +bool JVMFlag::is_ccstr() const { + return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; +} + +bool JVMFlag::ccstr_accumulates() const { + return strcmp(_type, "ccstrlist") == 0; +} + +ccstr JVMFlag::get_ccstr() const { + return *((ccstr*) _addr); +} + +JVMFlag::Error JVMFlag::set_ccstr(ccstr value) { + JVMFlag::Error error = check_writable(value!=get_ccstr()); + if (error == JVMFlag::SUCCESS) { + *((ccstr*) _addr) = value; + } + return error; +} + + +JVMFlag::Flags JVMFlag::get_origin() { + return Flags(_flags & VALUE_ORIGIN_MASK); +} + +void JVMFlag::set_origin(Flags origin) { + assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); + Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); + _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); +} + +bool JVMFlag::is_default() { + return (get_origin() == DEFAULT); +} + +bool JVMFlag::is_ergonomic() { + return (get_origin() == ERGONOMIC); +} + +bool JVMFlag::is_command_line() { + return (_flags & ORIG_COMMAND_LINE) != 0; +} + +void JVMFlag::set_command_line() { + _flags = Flags(_flags | ORIG_COMMAND_LINE); +} + +bool JVMFlag::is_product() const { + return (_flags & KIND_PRODUCT) != 0; +} + +bool JVMFlag::is_manageable() const { + return (_flags & KIND_MANAGEABLE) != 0; +} + +bool JVMFlag::is_diagnostic() const { + return (_flags & KIND_DIAGNOSTIC) != 0; +} + +bool JVMFlag::is_experimental() const { + return (_flags & KIND_EXPERIMENTAL) != 0; +} + +bool JVMFlag::is_notproduct() const { + return (_flags & KIND_NOT_PRODUCT) != 0; +} + +bool JVMFlag::is_develop() const { + return (_flags & KIND_DEVELOP) != 0; +} + +bool JVMFlag::is_read_write() const { + return (_flags & KIND_READ_WRITE) != 0; +} + +bool JVMFlag::is_commercial() const { + return (_flags & KIND_COMMERCIAL) != 0; +} + +/** + * Returns if this flag is a constant in the binary. Right now this is + * true for notproduct and develop flags in product builds. + */ +bool JVMFlag::is_constant_in_binary() const { +#ifdef PRODUCT + return is_notproduct() || is_develop(); +#else + return false; +#endif +} + +bool JVMFlag::is_unlocker() const { + return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || + strcmp(_name, "UnlockExperimentalVMOptions") == 0 || + is_unlocker_ext(); +} + +bool JVMFlag::is_unlocked() const { + if (is_diagnostic()) { + return UnlockDiagnosticVMOptions; + } + if (is_experimental()) { + return UnlockExperimentalVMOptions; + } + return is_unlocked_ext(); +} + +void JVMFlag::clear_diagnostic() { + assert(is_diagnostic(), "sanity"); + _flags = Flags(_flags & ~KIND_DIAGNOSTIC); + assert(!is_diagnostic(), "sanity"); +} + +// Get custom message for this locked flag, or NULL if +// none is available. Returns message type produced. +JVMFlag::MsgType JVMFlag::get_locked_message(char* buf, int buflen) const { + buf[0] = '\0'; + if (is_diagnostic() && !is_unlocked()) { + jio_snprintf(buf, buflen, + "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" + "Error: The unlock option must precede '%s'.\n", + _name, _name); + return JVMFlag::DIAGNOSTIC_FLAG_BUT_LOCKED; + } + if (is_experimental() && !is_unlocked()) { + jio_snprintf(buf, buflen, + "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" + "Error: The unlock option must precede '%s'.\n", + _name, _name); + return JVMFlag::EXPERIMENTAL_FLAG_BUT_LOCKED; + } + if (is_develop() && is_product_build()) { + jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", + _name); + return JVMFlag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; + } + if (is_notproduct() && is_product_build()) { + jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", + _name); + return JVMFlag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; + } + return get_locked_message_ext(buf, buflen); +} + +bool JVMFlag::is_writeable() const { + return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); +} + +// All flags except "manageable" are assumed to be internal flags. +// Long term, we need to define a mechanism to specify which flags +// are external/stable and change this function accordingly. +bool JVMFlag::is_external() const { + return is_manageable() || is_external_ext(); +} + +// Helper function for JVMFlag::print_on(). +// Fills current line up to requested position. +// Should the current position already be past the requested position, +// one separator blank is enforced. +void fill_to_pos(outputStream* st, unsigned int req_pos) { + if ((unsigned int)st->position() < req_pos) { + st->fill_to(req_pos); // need to fill with blanks to reach req_pos + } else { + st->print(" "); // enforce blank separation. Previous field too long. + } +} + +void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) { + // Don't print notproduct and develop flags in a product build. + if (is_constant_in_binary()) { + return; + } + + if (!printRanges) { + // The command line options -XX:+PrintFlags* cause this function to be called + // for each existing flag to print information pertinent to this flag. The data + // is displayed in columnar form, with the following layout: + // col1 - data type, right-justified + // col2 - name, left-justified + // col3 - ' =' double-char, leading space to align with possible '+=' + // col4 - value left-justified + // col5 - kind right-justified + // col6 - origin left-justified + // col7 - comments left-justified + // + // The column widths are fixed. They are defined such that, for most cases, + // an eye-pleasing tabular output is created. + // + // Sample output: + // bool CMSScavengeBeforeRemark = false {product} {default} + // uintx CMSScheduleRemarkEdenPenetration = 50 {product} {default} + // size_t CMSScheduleRemarkEdenSizeThreshold = 2097152 {product} {default} + // uintx CMSScheduleRemarkSamplingRatio = 5 {product} {default} + // double CMSSmallCoalSurplusPercent = 1.050000 {product} {default} + // ccstr CompileCommandFile = MyFile.cmd {product} {command line} + // ccstrlist CompileOnly = Method1 + // CompileOnly += Method2 {product} {command line} + // | | | | | | | + // | | | | | | +-- col7 + // | | | | | +-- col6 + // | | | | +-- col5 + // | | | +-- col4 + // | | +-- col3 + // | +-- col2 + // +-- col1 + + const unsigned int col_spacing = 1; + const unsigned int col1_pos = 0; + const unsigned int col1_width = 9; + const unsigned int col2_pos = col1_pos + col1_width + col_spacing; + const unsigned int col2_width = 39; + const unsigned int col3_pos = col2_pos + col2_width + col_spacing; + const unsigned int col3_width = 2; + const unsigned int col4_pos = col3_pos + col3_width + col_spacing; + const unsigned int col4_width = 30; + const unsigned int col5_pos = col4_pos + col4_width + col_spacing; + const unsigned int col5_width = 20; + const unsigned int col6_pos = col5_pos + col5_width + col_spacing; + const unsigned int col6_width = 15; + const unsigned int col7_pos = col6_pos + col6_width + col_spacing; + const unsigned int col7_width = 1; + + st->fill_to(col1_pos); + st->print("%*s", col1_width, _type); // right-justified, therefore width is required. + + fill_to_pos(st, col2_pos); + st->print("%s", _name); + + fill_to_pos(st, col3_pos); + st->print(" ="); // use " =" for proper alignment with multiline ccstr output. + + fill_to_pos(st, col4_pos); + if (is_bool()) { + st->print("%s", get_bool() ? "true" : "false"); + } else if (is_int()) { + st->print("%d", get_int()); + } else if (is_uint()) { + st->print("%u", get_uint()); + } else if (is_intx()) { + st->print(INTX_FORMAT, get_intx()); + } else if (is_uintx()) { + st->print(UINTX_FORMAT, get_uintx()); + } else if (is_uint64_t()) { + st->print(UINT64_FORMAT, get_uint64_t()); + } else if (is_size_t()) { + st->print(SIZE_FORMAT, get_size_t()); + } else if (is_double()) { + st->print("%f", get_double()); + } else if (is_ccstr()) { + // Honor characters in ccstr: print multiple lines. + const char* cp = get_ccstr(); + if (cp != NULL) { + const char* eol; + while ((eol = strchr(cp, '\n')) != NULL) { + size_t llen = pointer_delta(eol, cp, sizeof(char)); + st->print("%.*s", (int)llen, cp); + st->cr(); + cp = eol+1; + fill_to_pos(st, col2_pos); + st->print("%s", _name); + fill_to_pos(st, col3_pos); + st->print("+="); + fill_to_pos(st, col4_pos); + } + st->print("%s", cp); + } + } else { + st->print("unhandled type %s", _type); + st->cr(); + return; + } + + fill_to_pos(st, col5_pos); + print_kind(st, col5_width); + + fill_to_pos(st, col6_pos); + print_origin(st, col6_width); + +#ifndef PRODUCT + if (withComments) { + fill_to_pos(st, col7_pos); + st->print("%s", _doc); + } +#endif + st->cr(); + } else if (!is_bool() && !is_ccstr()) { + // The command line options -XX:+PrintFlags* cause this function to be called + // for each existing flag to print information pertinent to this flag. The data + // is displayed in columnar form, with the following layout: + // col1 - data type, right-justified + // col2 - name, left-justified + // col4 - range [ min ... max] + // col5 - kind right-justified + // col6 - origin left-justified + // col7 - comments left-justified + // + // The column widths are fixed. They are defined such that, for most cases, + // an eye-pleasing tabular output is created. + // + // Sample output: + // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} + // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} + // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} + // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} + // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} + // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} + // | | | | | | + // | | | | | +-- col7 + // | | | | +-- col6 + // | | | +-- col5 + // | | +-- col4 + // | +-- col2 + // +-- col1 + + const unsigned int col_spacing = 1; + const unsigned int col1_pos = 0; + const unsigned int col1_width = 9; + const unsigned int col2_pos = col1_pos + col1_width + col_spacing; + const unsigned int col2_width = 49; + const unsigned int col3_pos = col2_pos + col2_width + col_spacing; + const unsigned int col3_width = 0; + const unsigned int col4_pos = col3_pos + col3_width + col_spacing; + const unsigned int col4_width = 60; + const unsigned int col5_pos = col4_pos + col4_width + col_spacing; + const unsigned int col5_width = 35; + const unsigned int col6_pos = col5_pos + col5_width + col_spacing; + const unsigned int col6_width = 15; + const unsigned int col7_pos = col6_pos + col6_width + col_spacing; + const unsigned int col7_width = 1; + + st->fill_to(col1_pos); + st->print("%*s", col1_width, _type); // right-justified, therefore width is required. + + fill_to_pos(st, col2_pos); + st->print("%s", _name); + + fill_to_pos(st, col4_pos); + RangeStrFunc func = NULL; + if (is_int()) { + func = JVMFlag::get_int_default_range_str; + } else if (is_uint()) { + func = JVMFlag::get_uint_default_range_str; + } else if (is_intx()) { + func = JVMFlag::get_intx_default_range_str; + } else if (is_uintx()) { + func = JVMFlag::get_uintx_default_range_str; + } else if (is_uint64_t()) { + func = JVMFlag::get_uint64_t_default_range_str; + } else if (is_size_t()) { + func = JVMFlag::get_size_t_default_range_str; + } else if (is_double()) { + func = JVMFlag::get_double_default_range_str; + } else { + st->print("unhandled type %s", _type); + st->cr(); + return; + } + JVMFlagRangeList::print(st, _name, func); + + fill_to_pos(st, col5_pos); + print_kind(st, col5_width); + + fill_to_pos(st, col6_pos); + print_origin(st, col6_width); + +#ifndef PRODUCT + if (withComments) { + fill_to_pos(st, col7_pos); + st->print("%s", _doc); + } +#endif + st->cr(); + } +} + +void JVMFlag::print_kind(outputStream* st, unsigned int width) { + struct Data { + int flag; + const char* name; + }; + + Data data[] = { + { KIND_JVMCI, "JVMCI" }, + { KIND_C1, "C1" }, + { KIND_C2, "C2" }, + { KIND_ARCH, "ARCH" }, + { KIND_PLATFORM_DEPENDENT, "pd" }, + { KIND_PRODUCT, "product" }, + { KIND_MANAGEABLE, "manageable" }, + { KIND_DIAGNOSTIC, "diagnostic" }, + { KIND_EXPERIMENTAL, "experimental" }, + { KIND_COMMERCIAL, "commercial" }, + { KIND_NOT_PRODUCT, "notproduct" }, + { KIND_DEVELOP, "develop" }, + { KIND_LP64_PRODUCT, "lp64_product" }, + { KIND_READ_WRITE, "rw" }, + { -1, "" } + }; + + if ((_flags & KIND_MASK) != 0) { + bool is_first = true; + const size_t buffer_size = 64; + size_t buffer_used = 0; + char kind[buffer_size]; + + jio_snprintf(kind, buffer_size, "{"); + buffer_used++; + for (int i = 0; data[i].flag != -1; i++) { + Data d = data[i]; + if ((_flags & d.flag) != 0) { + if (is_first) { + is_first = false; + } else { + assert(buffer_used + 1 < buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); + buffer_used++; + } + size_t length = strlen(d.name); + assert(buffer_used + length < buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); + buffer_used += length; + } + } + assert(buffer_used + 2 <= buffer_size, "Too small buffer"); + jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); + st->print("%*s", width, kind); + } +} + +void JVMFlag::print_origin(outputStream* st, unsigned int width) { + int origin = _flags & VALUE_ORIGIN_MASK; + st->print("{"); + switch(origin) { + case DEFAULT: + st->print("default"); break; + case COMMAND_LINE: + st->print("command line"); break; + case ENVIRON_VAR: + st->print("environment"); break; + case CONFIG_FILE: + st->print("config file"); break; + case MANAGEMENT: + st->print("management"); break; + case ERGONOMIC: + if (_flags & ORIG_COMMAND_LINE) { + st->print("command line, "); + } + st->print("ergonomic"); break; + case ATTACH_ON_DEMAND: + st->print("attach"); break; + case INTERNAL: + st->print("internal"); break; + } + st->print("}"); +} + +void JVMFlag::print_as_flag(outputStream* st) { + if (is_bool()) { + st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); + } else if (is_int()) { + st->print("-XX:%s=%d", _name, get_int()); + } else if (is_uint()) { + st->print("-XX:%s=%u", _name, get_uint()); + } else if (is_intx()) { + st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); + } else if (is_uintx()) { + st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); + } else if (is_uint64_t()) { + st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); + } else if (is_size_t()) { + st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); + } else if (is_double()) { + st->print("-XX:%s=%f", _name, get_double()); + } else if (is_ccstr()) { + st->print("-XX:%s=", _name); + const char* cp = get_ccstr(); + if (cp != NULL) { + // Need to turn embedded '\n's back into separate arguments + // Not so efficient to print one character at a time, + // but the choice is to do the transformation to a buffer + // and print that. And this need not be efficient. + for (; *cp != '\0'; cp += 1) { + switch (*cp) { + default: + st->print("%c", *cp); + break; + case '\n': + st->print(" -XX:%s=", _name); + break; + } + } + } + } else { + ShouldNotReachHere(); + } +} + +const char* JVMFlag::flag_error_str(JVMFlag::Error error) { + switch (error) { + case JVMFlag::MISSING_NAME: return "MISSING_NAME"; + case JVMFlag::MISSING_VALUE: return "MISSING_VALUE"; + case JVMFlag::NON_WRITABLE: return "NON_WRITABLE"; + case JVMFlag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; + case JVMFlag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; + case JVMFlag::INVALID_FLAG: return "INVALID_FLAG"; + case JVMFlag::ERR_OTHER: return "ERR_OTHER"; + case JVMFlag::SUCCESS: return "SUCCESS"; + default: ShouldNotReachHere(); return "NULL"; + } +} + +// 4991491 do not "optimize out" the was_set false values: omitting them +// tickles a Microsoft compiler bug causing flagTable to be malformed + +#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT) }, +#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DIAGNOSTIC) }, +#define RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_EXPERIMENTAL) }, +#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_MANAGEABLE) }, +#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_READ_WRITE) }, +#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DEVELOP) }, +#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_NOT_PRODUCT) }, + +#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_PRODUCT) }, +#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DIAGNOSTIC) }, +#define JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_EXPERIMENTAL) }, +#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DEVELOP) }, +#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_JVMCI | JVMFlag::KIND_NOT_PRODUCT) }, + +#ifdef _LP64 +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_LP64_PRODUCT) }, +#else +#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ +#endif // _LP64 + +#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_PRODUCT) }, +#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DIAGNOSTIC) }, +#define C1_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DEVELOP) }, +#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C1 | JVMFlag::KIND_NOT_PRODUCT) }, + +#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_PRODUCT) }, +#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_PRODUCT | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DIAGNOSTIC) }, +#define C2_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_EXPERIMENTAL) }, +#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DEVELOP) }, +#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_DEVELOP | JVMFlag::KIND_PLATFORM_DEPENDENT) }, +#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_C2 | JVMFlag::KIND_NOT_PRODUCT) }, + +#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_PRODUCT) }, +#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_DIAGNOSTIC) }, +#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_EXPERIMENTAL) }, +#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_DEVELOP) }, +#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) JVMFlag::Flags(JVMFlag::DEFAULT | JVMFlag::KIND_ARCH | JVMFlag::KIND_NOT_PRODUCT) }, + +static JVMFlag flagTable[] = { + VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PRODUCT_FLAG_STRUCT, \ + RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ + RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \ + RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ + RUNTIME_MANAGEABLE_FLAG_STRUCT, \ + RUNTIME_PRODUCT_RW_FLAG_STRUCT, \ + RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) + + RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ + RUNTIME_PRODUCT_FLAG_STRUCT, \ + RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ + RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ + RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ + JVMCI_PD_DEVELOP_FLAG_STRUCT, \ + JVMCI_PRODUCT_FLAG_STRUCT, \ + JVMCI_PD_PRODUCT_FLAG_STRUCT, \ + JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ + JVMCI_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // INCLUDE_JVMCI +#ifdef COMPILER1 + C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ + C1_PD_DEVELOP_FLAG_STRUCT, \ + C1_PRODUCT_FLAG_STRUCT, \ + C1_PD_PRODUCT_FLAG_STRUCT, \ + C1_DIAGNOSTIC_FLAG_STRUCT, \ + C1_PD_DIAGNOSTIC_FLAG_STRUCT, \ + C1_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // COMPILER1 +#ifdef COMPILER2 + C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \ + C2_PD_DEVELOP_FLAG_STRUCT, \ + C2_PRODUCT_FLAG_STRUCT, \ + C2_PD_PRODUCT_FLAG_STRUCT, \ + C2_DIAGNOSTIC_FLAG_STRUCT, \ + C2_PD_DIAGNOSTIC_FLAG_STRUCT, \ + C2_EXPERIMENTAL_FLAG_STRUCT, \ + C2_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) +#endif // COMPILER2 + ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ + ARCH_PRODUCT_FLAG_STRUCT, \ + ARCH_DIAGNOSTIC_FLAG_STRUCT, \ + ARCH_EXPERIMENTAL_FLAG_STRUCT, \ + ARCH_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT, \ + IGNORE_WRITEABLE) + FLAGTABLE_EXT + {0, NULL, NULL} +}; + +JVMFlag* JVMFlag::flags = flagTable; +size_t JVMFlag::numFlags = (sizeof(flagTable) / sizeof(JVMFlag)); + +inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { + if (s_len != q_len) return false; + return memcmp(s, q, q_len) == 0; +} + +// Search the flag table for a named flag +JVMFlag* JVMFlag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { + for (JVMFlag* current = &flagTable[0]; current->_name != NULL; current++) { + if (str_equal(current->_name, current->get_name_length(), name, length)) { + // Found a matching entry. + // Don't report notproduct and develop flags in product builds. + if (current->is_constant_in_binary()) { + return (return_flag ? current : NULL); + } + // Report locked flags only if allowed. + if (!(current->is_unlocked() || current->is_unlocker())) { + if (!allow_locked) { + // disable use of locked flags, e.g. diagnostic, experimental, + // commercial... until they are explicitly unlocked + return NULL; + } + } + return current; + } + } + // JVMFlag name is not in the flag table + return NULL; +} + +// Get or compute the flag name length +size_t JVMFlag::get_name_length() { + if (_name_len == 0) { + _name_len = strlen(_name); + } + return _name_len; +} + +JVMFlag* JVMFlag::fuzzy_match(const char* name, size_t length, bool allow_locked) { + float VMOptionsFuzzyMatchSimilarity = 0.7f; + JVMFlag* match = NULL; + float score; + float max_score = -1; + + for (JVMFlag* current = &flagTable[0]; current->_name != NULL; current++) { + score = StringUtils::similarity(current->_name, strlen(current->_name), name, length); + if (score > max_score) { + max_score = score; + match = current; + } + } + + if (!(match->is_unlocked() || match->is_unlocker())) { + if (!allow_locked) { + return NULL; + } + } + + if (max_score < VMOptionsFuzzyMatchSimilarity) { + return NULL; + } + + return match; +} + +// Returns the address of the index'th element +static JVMFlag* address_of_flag(JVMFlagsWithType flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + return &JVMFlag::flags[flag]; +} + +bool JVMFlagEx::is_default(JVMFlags flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + JVMFlag* f = &JVMFlag::flags[flag]; + return f->is_default(); +} + +bool JVMFlagEx::is_ergo(JVMFlags flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + JVMFlag* f = &JVMFlag::flags[flag]; + return f->is_ergonomic(); +} + +bool JVMFlagEx::is_cmdline(JVMFlags flag) { + assert((size_t)flag < JVMFlag::numFlags, "bad command line flag index"); + JVMFlag* f = &JVMFlag::flags[flag]; + return f->is_command_line(); +} + +bool JVMFlag::wasSetOnCmdline(const char* name, bool* value) { + JVMFlag* result = JVMFlag::find_flag((char*)name, strlen(name)); + if (result == NULL) return false; + *value = result->is_command_line(); + return true; +} + +void JVMFlagEx::setOnCmdLine(JVMFlagsWithType flag) { + JVMFlag* faddr = address_of_flag(flag); + assert(faddr != NULL, "Unknown flag"); + faddr->set_command_line(); +} + +template +static void trace_flag_changed(const char* name, const T old_value, const T new_value, const JVMFlag::Flags origin) { + E e; + e.set_name(name); + e.set_oldValue(old_value); + e.set_newValue(new_value); + e.set_origin(origin); + e.commit(); +} + +static JVMFlag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_bool(new_value, verbose); + } + return status; +} + +JVMFlag::Error JVMFlag::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_bool()) return JVMFlag::WRONG_FORMAT; + *value = result->get_bool(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::boolAtPut(JVMFlag* flag, bool* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_bool()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_bool(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + bool old_value = flag->get_bool(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_bool(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::boolAtPut(const char* name, size_t len, bool* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return boolAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); + return JVMFlag::boolAtPut(faddr, &value, origin); +} + +static JVMFlag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_int(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_int(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_int()) return JVMFlag::WRONG_FORMAT; + *value = result->get_int(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_int()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_int(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + int old_value = flag->get_int(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_int(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::intAtPut(const char* name, size_t len, int* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return intAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_int(), "wrong flag type"); + return JVMFlag::intAtPut(faddr, &value, origin); +} + +static JVMFlag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uint(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uint(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_uint()) return JVMFlag::WRONG_FORMAT; + *value = result->get_uint(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_uint()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_uint(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + uint old_value = flag->get_uint(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uint(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::uintAtPut(const char* name, size_t len, uint* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return uintAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type"); + return JVMFlag::uintAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_intx()) return JVMFlag::WRONG_FORMAT; + *value = result->get_intx(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_intx(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_intx(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_intx()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_intx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + intx old_value = flag->get_intx(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_intx(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::intxAtPut(const char* name, size_t len, intx* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return intxAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); + return JVMFlag::intxAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_uintx()) return JVMFlag::WRONG_FORMAT; + *value = result->get_uintx(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uintx(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uintx(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_uintx()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_uintx(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + uintx old_value = flag->get_uintx(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uintx(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::uintxAtPut(const char* name, size_t len, uintx* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return uintxAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); + return JVMFlag::uintxAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_uint64_t()) return JVMFlag::WRONG_FORMAT; + *value = result->get_uint64_t(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_uint64_t(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_uint64_t(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_uint64_t()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + uint64_t old_value = flag->get_uint64_t(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_uint64_t(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::uint64_tAtPut(const char* name, size_t len, uint64_t* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return uint64_tAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); + return JVMFlag::uint64_tAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_size_t()) return JVMFlag::WRONG_FORMAT; + *value = result->get_size_t(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_size_t(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_size_t(new_value, verbose); + } + } + return status; +} + + +JVMFlag::Error JVMFlag::size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_size_t()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_size_t(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + size_t old_value = flag->get_size_t(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_size_t(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::size_tAtPut(const char* name, size_t len, size_t* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return size_tAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); + return JVMFlag::size_tAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_double()) return JVMFlag::WRONG_FORMAT; + *value = result->get_double(); + return JVMFlag::SUCCESS; +} + +static JVMFlag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) { + JVMFlag::Error status = JVMFlag::SUCCESS; + JVMFlagRange* range = JVMFlagRangeList::find(name); + if (range != NULL) { + status = range->check_double(new_value, verbose); + } + if (status == JVMFlag::SUCCESS) { + JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(name); + if (constraint != NULL) { + status = constraint->apply_double(new_value, verbose); + } + } + return status; +} + +JVMFlag::Error JVMFlag::doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags origin) { + const char* name; + if (flag == NULL) return JVMFlag::INVALID_FLAG; + if (!flag->is_double()) return JVMFlag::WRONG_FORMAT; + name = flag->_name; + JVMFlag::Error check = apply_constraint_and_check_range_double(name, *value, !JVMFlagConstraintList::validated_after_ergo()); + if (check != JVMFlag::SUCCESS) return check; + double old_value = flag->get_double(); + trace_flag_changed(name, old_value, *value, origin); + check = flag->set_double(*value); + *value = old_value; + flag->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlag::doubleAtPut(const char* name, size_t len, double* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + return doubleAtPut(result, value, origin); +} + +JVMFlag::Error JVMFlagEx::doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); + return JVMFlag::doubleAtPut(faddr, &value, origin); +} + +JVMFlag::Error JVMFlag::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) { + JVMFlag* result = JVMFlag::find_flag(name, len, allow_locked, return_flag); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_ccstr()) return JVMFlag::WRONG_FORMAT; + *value = result->get_ccstr(); + return JVMFlag::SUCCESS; +} + +JVMFlag::Error JVMFlag::ccstrAtPut(const char* name, size_t len, ccstr* value, JVMFlag::Flags origin) { + JVMFlag* result = JVMFlag::find_flag(name, len); + if (result == NULL) return JVMFlag::INVALID_FLAG; + if (!result->is_ccstr()) return JVMFlag::WRONG_FORMAT; + ccstr old_value = result->get_ccstr(); + trace_flag_changed(name, old_value, *value, origin); + char* new_value = NULL; + if (*value != NULL) { + new_value = os::strdup_check_oom(*value); + } + JVMFlag::Error check = result->set_ccstr(new_value); + if (result->is_default() && old_value != NULL) { + // Prior value is NOT heap allocated, but was a literal constant. + old_value = os::strdup_check_oom(old_value); + } + *value = old_value; + result->set_origin(origin); + return check; +} + +JVMFlag::Error JVMFlagEx::ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin) { + JVMFlag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); + ccstr old_value = faddr->get_ccstr(); + trace_flag_changed(faddr->_name, old_value, value, origin); + char* new_value = os::strdup_check_oom(value); + JVMFlag::Error check = faddr->set_ccstr(new_value); + if (!faddr->is_default() && old_value != NULL) { + // Prior value is heap allocated so free it. + FREE_C_HEAP_ARRAY(char, old_value); + } + faddr->set_origin(origin); + return check; +} + +extern "C" { + static int compare_flags(const void* void_a, const void* void_b) { + return strcmp((*((JVMFlag**) void_a))->_name, (*((JVMFlag**) void_b))->_name); + } +} + +void JVMFlag::printSetFlags(outputStream* out) { + // Print which flags were set on the command line + // note: this method is called before the thread structure is in place + // which means resource allocation cannot be used. + + // The last entry is the null entry. + const size_t length = JVMFlag::numFlags - 1; + + // Sort + JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; + } + qsort(array, length, sizeof(JVMFlag*), compare_flags); + + // Print + for (size_t i = 0; i < length; i++) { + if (array[i]->get_origin() /* naked field! */) { + array[i]->print_as_flag(out); + out->print(" "); + } + } + out->cr(); + FREE_C_HEAP_ARRAY(JVMFlag*, array); +} + +#ifndef PRODUCT + +void JVMFlag::verify() { + assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); +} + +#endif // PRODUCT + +void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges) { + // Print the flags sorted by name + // note: this method is called before the thread structure is in place + // which means resource allocation cannot be used. + + // The last entry is the null entry. + const size_t length = JVMFlag::numFlags - 1; + + // Sort + JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments); + for (size_t i = 0; i < length; i++) { + array[i] = &flagTable[i]; + } + qsort(array, length, sizeof(JVMFlag*), compare_flags); + + // Print + if (!printRanges) { + out->print_cr("[Global flags]"); + } else { + out->print_cr("[Global flags ranges]"); + } + + for (size_t i = 0; i < length; i++) { + if (array[i]->is_unlocked()) { + array[i]->print_on(out, withComments, printRanges); + } + } + FREE_C_HEAP_ARRAY(JVMFlag*, array); +} + diff --git a/src/hotspot/share/runtime/flags/jvmFlag.hpp b/src/hotspot/share/runtime/flags/jvmFlag.hpp new file mode 100644 index 00000000000..e8c8210bd06 --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlag.hpp @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP +#define SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// function type that will construct default range string +typedef const char* (*RangeStrFunc)(void); + +struct JVMFlag { + enum Flags { + // latest value origin + DEFAULT = 0, + COMMAND_LINE = 1, + ENVIRON_VAR = 2, + CONFIG_FILE = 3, + MANAGEMENT = 4, + ERGONOMIC = 5, + ATTACH_ON_DEMAND = 6, + INTERNAL = 7, + + LAST_VALUE_ORIGIN = INTERNAL, + VALUE_ORIGIN_BITS = 4, + VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), + + // flag kind + KIND_PRODUCT = 1 << 4, + KIND_MANAGEABLE = 1 << 5, + KIND_DIAGNOSTIC = 1 << 6, + KIND_EXPERIMENTAL = 1 << 7, + KIND_NOT_PRODUCT = 1 << 8, + KIND_DEVELOP = 1 << 9, + KIND_PLATFORM_DEPENDENT = 1 << 10, + KIND_READ_WRITE = 1 << 11, + KIND_C1 = 1 << 12, + KIND_C2 = 1 << 13, + KIND_ARCH = 1 << 14, + KIND_LP64_PRODUCT = 1 << 15, + KIND_COMMERCIAL = 1 << 16, + KIND_JVMCI = 1 << 17, + + // set this bit if the flag was set on the command line + ORIG_COMMAND_LINE = 1 << 18, + + KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) + }; + + enum Error { + // no error + SUCCESS = 0, + // flag name is missing + MISSING_NAME, + // flag value is missing + MISSING_VALUE, + // error parsing the textual form of the value + WRONG_FORMAT, + // flag is not writable + NON_WRITABLE, + // flag value is outside of its bounds + OUT_OF_BOUNDS, + // flag value violates its constraint + VIOLATES_CONSTRAINT, + // there is no flag with the given name + INVALID_FLAG, + // the flag can only be set only on command line during invocation of the VM + COMMAND_LINE_ONLY, + // the flag may only be set once + SET_ONLY_ONCE, + // the flag is not writable in this combination of product/debug build + CONSTANT, + // other, unspecified error related to setting the flag + ERR_OTHER + }; + + enum MsgType { + NONE = 0, + DIAGNOSTIC_FLAG_BUT_LOCKED, + EXPERIMENTAL_FLAG_BUT_LOCKED, + DEVELOPER_FLAG_BUT_PRODUCT_BUILD, + NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD, + COMMERCIAL_FLAG_BUT_DISABLED, + COMMERCIAL_FLAG_BUT_LOCKED + }; + + const char* _type; + const char* _name; + void* _addr; + NOT_PRODUCT(const char* _doc;) + Flags _flags; + size_t _name_len; + + // points to all Flags static array + static JVMFlag* flags; + + // number of flags + static size_t numFlags; + + static JVMFlag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); }; + static JVMFlag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); + static JVMFlag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); + + static const char* get_int_default_range_str(); + static const char* get_uint_default_range_str(); + static const char* get_intx_default_range_str(); + static const char* get_uintx_default_range_str(); + static const char* get_uint64_t_default_range_str(); + static const char* get_size_t_default_range_str(); + static const char* get_double_default_range_str(); + + JVMFlag::Error check_writable(bool changed); + + bool is_bool() const; + bool get_bool() const; + JVMFlag::Error set_bool(bool value); + + bool is_int() const; + int get_int() const; + JVMFlag::Error set_int(int value); + + bool is_uint() const; + uint get_uint() const; + JVMFlag::Error set_uint(uint value); + + bool is_intx() const; + intx get_intx() const; + JVMFlag::Error set_intx(intx value); + + bool is_uintx() const; + uintx get_uintx() const; + JVMFlag::Error set_uintx(uintx value); + + bool is_uint64_t() const; + uint64_t get_uint64_t() const; + JVMFlag::Error set_uint64_t(uint64_t value); + + bool is_size_t() const; + size_t get_size_t() const; + JVMFlag::Error set_size_t(size_t value); + + bool is_double() const; + double get_double() const; + JVMFlag::Error set_double(double value); + + bool is_ccstr() const; + bool ccstr_accumulates() const; + ccstr get_ccstr() const; + JVMFlag::Error set_ccstr(ccstr value); + + Flags get_origin(); + void set_origin(Flags origin); + + size_t get_name_length(); + + bool is_default(); + bool is_ergonomic(); + bool is_command_line(); + void set_command_line(); + + bool is_product() const; + bool is_manageable() const; + bool is_diagnostic() const; + bool is_experimental() const; + bool is_notproduct() const; + bool is_develop() const; + bool is_read_write() const; + bool is_commercial() const; + + bool is_constant_in_binary() const; + + bool is_unlocker() const; + bool is_unlocked() const; + bool is_writeable() const; + bool is_external() const; + + bool is_unlocker_ext() const; + bool is_unlocked_ext() const; + bool is_writeable_ext() const; + bool is_external_ext() const; + + void clear_diagnostic(); + + JVMFlag::MsgType get_locked_message(char*, int) const; + JVMFlag::MsgType get_locked_message_ext(char*, int) const; + + // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges + void print_on(outputStream* st, bool withComments = false, bool printRanges = false); + void print_kind(outputStream* st, unsigned int width); + void print_origin(outputStream* st, unsigned int width); + void print_as_flag(outputStream* st); + + static const char* flag_error_str(JVMFlag::Error error); + +public: + static JVMFlag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error boolAtPut(JVMFlag* flag, bool* value, JVMFlag::Flags origin); + static JVMFlag::Error boolAtPut(const char* name, size_t len, bool* value, JVMFlag::Flags origin); + static JVMFlag::Error boolAtPut(const char* name, bool* value, JVMFlag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error intAtPut(JVMFlag* flag, int* value, JVMFlag::Flags origin); + static JVMFlag::Error intAtPut(const char* name, size_t len, int* value, JVMFlag::Flags origin); + static JVMFlag::Error intAtPut(const char* name, int* value, JVMFlag::Flags origin) { return intAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error uintAtPut(JVMFlag* flag, uint* value, JVMFlag::Flags origin); + static JVMFlag::Error uintAtPut(const char* name, size_t len, uint* value, JVMFlag::Flags origin); + static JVMFlag::Error uintAtPut(const char* name, uint* value, JVMFlag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error intxAtPut(JVMFlag* flag, intx* value, JVMFlag::Flags origin); + static JVMFlag::Error intxAtPut(const char* name, size_t len, intx* value, JVMFlag::Flags origin); + static JVMFlag::Error intxAtPut(const char* name, intx* value, JVMFlag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error uintxAtPut(JVMFlag* flag, uintx* value, JVMFlag::Flags origin); + static JVMFlag::Error uintxAtPut(const char* name, size_t len, uintx* value, JVMFlag::Flags origin); + static JVMFlag::Error uintxAtPut(const char* name, uintx* value, JVMFlag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin); + static JVMFlag::Error size_tAtPut(const char* name, size_t len, size_t* value, JVMFlag::Flags origin); + static JVMFlag::Error size_tAtPut(const char* name, size_t* value, JVMFlag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error uint64_tAtPut(JVMFlag* flag, uint64_t* value, JVMFlag::Flags origin); + static JVMFlag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, JVMFlag::Flags origin); + static JVMFlag::Error uint64_tAtPut(const char* name, uint64_t* value, JVMFlag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); } + static JVMFlag::Error doubleAtPut(JVMFlag* flag, double* value, JVMFlag::Flags origin); + static JVMFlag::Error doubleAtPut(const char* name, size_t len, double* value, JVMFlag::Flags origin); + static JVMFlag::Error doubleAtPut(const char* name, double* value, JVMFlag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } + + static JVMFlag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false); + static JVMFlag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); } + // Contract: JVMFlag will make private copy of the incoming value. + // Outgoing value is always malloc-ed, and caller MUST call free. + static JVMFlag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, JVMFlag::Flags origin); + static JVMFlag::Error ccstrAtPut(const char* name, ccstr* value, JVMFlag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } + + // Returns false if name is not a command line flag. + static bool wasSetOnCmdline(const char* name, bool* value); + static void printSetFlags(outputStream* out); + + // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges + static void printFlags(outputStream* out, bool withComments, bool printRanges = false); + + static void verify() PRODUCT_RETURN; +}; + +#endif // SHARE_VM_RUNTIME_FLAGS_JVMFLAG_HPP diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp similarity index 58% rename from src/hotspot/share/runtime/commandLineFlagConstraintList.cpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp index c900c2e4e1a..a0832397585 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.cpp @@ -25,11 +25,12 @@ #include "precompiled.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" -#include "gc/shared/commandLineFlagConstraintsGC.hpp" +#include "gc/shared/jvmFlagConstraintsGC.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagConstraintsCompiler.hpp" -#include "runtime/commandLineFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagConstraintsCompiler.hpp" +#include "runtime/flags/jvmFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" #ifdef COMPILER1 @@ -39,162 +40,161 @@ #include "opto/c2_globals.hpp" #endif - -class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_bool _constraint; +class JVMFlagConstraint_bool : public JVMFlagConstraint { + JVMFlagConstraintFunc_bool _constraint; const bool* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_bool(const char* name, const bool* ptr, - CommandLineFlagConstraintFunc_bool func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_bool(const char* name, const bool* ptr, + JVMFlagConstraintFunc_bool func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { bool value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_bool(bool value, bool verbose) { + JVMFlag::Error apply_bool(bool value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_int : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_int _constraint; +class JVMFlagConstraint_int : public JVMFlagConstraint { + JVMFlagConstraintFunc_int _constraint; const int* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_int(const char* name, const int* ptr, - CommandLineFlagConstraintFunc_int func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_int(const char* name, const int* ptr, + JVMFlagConstraintFunc_int func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { int value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_int(int value, bool verbose) { + JVMFlag::Error apply_int(int value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_intx : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_intx _constraint; +class JVMFlagConstraint_intx : public JVMFlagConstraint { + JVMFlagConstraintFunc_intx _constraint; const intx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_intx(const char* name, const intx* ptr, - CommandLineFlagConstraintFunc_intx func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_intx(const char* name, const intx* ptr, + JVMFlagConstraintFunc_intx func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { intx value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_intx(intx value, bool verbose) { + JVMFlag::Error apply_intx(intx value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_uint : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_uint _constraint; +class JVMFlagConstraint_uint : public JVMFlagConstraint { + JVMFlagConstraintFunc_uint _constraint; const uint* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uint(const char* name, const uint* ptr, - CommandLineFlagConstraintFunc_uint func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_uint(const char* name, const uint* ptr, + JVMFlagConstraintFunc_uint func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { uint value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_uint(uint value, bool verbose) { + JVMFlag::Error apply_uint(uint value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_uintx : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_uintx _constraint; +class JVMFlagConstraint_uintx : public JVMFlagConstraint { + JVMFlagConstraintFunc_uintx _constraint; const uintx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uintx(const char* name, const uintx* ptr, - CommandLineFlagConstraintFunc_uintx func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_uintx(const char* name, const uintx* ptr, + JVMFlagConstraintFunc_uintx func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { uintx value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_uintx(uintx value, bool verbose) { + JVMFlag::Error apply_uintx(uintx value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_uint64_t : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_uint64_t _constraint; +class JVMFlagConstraint_uint64_t : public JVMFlagConstraint { + JVMFlagConstraintFunc_uint64_t _constraint; const uint64_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_uint64_t(const char* name, const uint64_t* ptr, - CommandLineFlagConstraintFunc_uint64_t func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_uint64_t(const char* name, const uint64_t* ptr, + JVMFlagConstraintFunc_uint64_t func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { uint64_t value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_uint64_t(uint64_t value, bool verbose) { + JVMFlag::Error apply_uint64_t(uint64_t value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_size_t : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_size_t _constraint; +class JVMFlagConstraint_size_t : public JVMFlagConstraint { + JVMFlagConstraintFunc_size_t _constraint; const size_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_size_t(const char* name, const size_t* ptr, - CommandLineFlagConstraintFunc_size_t func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_size_t(const char* name, const size_t* ptr, + JVMFlagConstraintFunc_size_t func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { size_t value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_size_t(size_t value, bool verbose) { + JVMFlag::Error apply_size_t(size_t value, bool verbose) { return _constraint(value, verbose); } }; -class CommandLineFlagConstraint_double : public CommandLineFlagConstraint { - CommandLineFlagConstraintFunc_double _constraint; +class JVMFlagConstraint_double : public JVMFlagConstraint { + JVMFlagConstraintFunc_double _constraint; const double* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagConstraint_double(const char* name, const double* ptr, - CommandLineFlagConstraintFunc_double func, - ConstraintType type) : CommandLineFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} + JVMFlagConstraint_double(const char* name, const double* ptr, + JVMFlagConstraintFunc_double func, + ConstraintType type) : JVMFlagConstraint(name, type), _constraint(func), _ptr(ptr) {} - Flag::Error apply(bool verbose) { + JVMFlag::Error apply(bool verbose) { double value = *_ptr; return _constraint(value, verbose); } - Flag::Error apply_double(double value, bool verbose) { + JVMFlag::Error apply_double(double value, bool verbose) { return _constraint(value, verbose); } }; @@ -214,30 +214,30 @@ void emit_constraint_uint64_t(const char* /*name*/, const uint64_t* /*value*/) void emit_constraint_size_t(const char* /*name*/, const size_t* /*value*/) { /* NOP */ } void emit_constraint_double(const char* /*name*/, const double* /*value*/) { /* NOP */ } -// CommandLineFlagConstraint emitting code functions if function argument is provided -void emit_constraint_bool(const char* name, const bool* ptr, CommandLineFlagConstraintFunc_bool func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_bool(name, ptr, func, type)); +// JVMFlagConstraint emitting code functions if function argument is provided +void emit_constraint_bool(const char* name, const bool* ptr, JVMFlagConstraintFunc_bool func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_bool(name, ptr, func, type)); } -void emit_constraint_int(const char* name, const int* ptr, CommandLineFlagConstraintFunc_int func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_int(name, ptr, func, type)); +void emit_constraint_int(const char* name, const int* ptr, JVMFlagConstraintFunc_int func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_int(name, ptr, func, type)); } -void emit_constraint_intx(const char* name, const intx* ptr, CommandLineFlagConstraintFunc_intx func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_intx(name, ptr, func, type)); +void emit_constraint_intx(const char* name, const intx* ptr, JVMFlagConstraintFunc_intx func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_intx(name, ptr, func, type)); } -void emit_constraint_uint(const char* name, const uint* ptr, CommandLineFlagConstraintFunc_uint func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint(name, ptr, func, type)); +void emit_constraint_uint(const char* name, const uint* ptr, JVMFlagConstraintFunc_uint func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_uint(name, ptr, func, type)); } -void emit_constraint_uintx(const char* name, const uintx* ptr, CommandLineFlagConstraintFunc_uintx func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uintx(name, ptr, func, type)); +void emit_constraint_uintx(const char* name, const uintx* ptr, JVMFlagConstraintFunc_uintx func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_uintx(name, ptr, func, type)); } -void emit_constraint_uint64_t(const char* name, const uint64_t* ptr, CommandLineFlagConstraintFunc_uint64_t func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint64_t(name, ptr, func, type)); +void emit_constraint_uint64_t(const char* name, const uint64_t* ptr, JVMFlagConstraintFunc_uint64_t func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_uint64_t(name, ptr, func, type)); } -void emit_constraint_size_t(const char* name, const size_t* ptr, CommandLineFlagConstraintFunc_size_t func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_size_t(name, ptr, func, type)); +void emit_constraint_size_t(const char* name, const size_t* ptr, JVMFlagConstraintFunc_size_t func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_size_t(name, ptr, func, type)); } -void emit_constraint_double(const char* name, const double* ptr, CommandLineFlagConstraintFunc_double func, CommandLineFlagConstraint::ConstraintType type) { - CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_double(name, ptr, func, type)); +void emit_constraint_double(const char* name, const double* ptr, JVMFlagConstraintFunc_double func, JVMFlagConstraint::ConstraintType type) { + JVMFlagConstraintList::add(new JVMFlagConstraint_double(name, ptr, func, type)); } // Generate code to call emit_constraint_xxx function @@ -265,16 +265,16 @@ void emit_constraint_double(const char* name, const double* ptr, CommandLineFlag #endif // Generate func argument to pass into emit_constraint_xxx functions -#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type +#define EMIT_CONSTRAINT_CHECK(func, type) , func, JVMFlagConstraint::type // the "name" argument must be a string literal #define INITIAL_CONSTRAINTS_SIZE 72 -GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; -CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; +GrowableArray* JVMFlagConstraintList::_constraints = NULL; +JVMFlagConstraint::ConstraintType JVMFlagConstraintList::_validating_type = JVMFlagConstraint::AtParse; // Check the ranges of all flags that have them or print them out and exit if requested -void CommandLineFlagConstraintList::init(void) { - _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); +void JVMFlagConstraintList::init(void) { + _constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_CONSTRAINTS_SIZE, true); emit_constraint_no(NULL VM_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, @@ -331,10 +331,10 @@ void CommandLineFlagConstraintList::init(void) { #endif // COMPILER2 } -CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) { - CommandLineFlagConstraint* found = NULL; +JVMFlagConstraint* JVMFlagConstraintList::find(const char* name) { + JVMFlagConstraint* found = NULL; for (int i=0; iname(), name) == 0) { found = constraint; break; @@ -344,9 +344,9 @@ CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) } // Find constraints by name and return only if found constraint's type is equal or lower than current validating type. -CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(const char* name) { - CommandLineFlagConstraint* found = NULL; - CommandLineFlagConstraint* constraint = find(name); +JVMFlagConstraint* JVMFlagConstraintList::find_if_needs_check(const char* name) { + JVMFlagConstraint* found = NULL; + JVMFlagConstraint* constraint = find(name); if (constraint && (constraint->type() <= _validating_type)) { found = constraint; } @@ -354,15 +354,15 @@ CommandLineFlagConstraint* CommandLineFlagConstraintList::find_if_needs_check(co } // Check constraints for specific constraint type. -bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { +bool JVMFlagConstraintList::check_constraints(JVMFlagConstraint::ConstraintType type) { guarantee(type > _validating_type, "Constraint check is out of order."); _validating_type = type; bool status = true; for (int i=0; itype()) continue; - if (constraint->apply(true) != Flag::SUCCESS) status = false; + if (constraint->apply(true) != JVMFlag::SUCCESS) status = false; } return status; } diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp new file mode 100644 index 00000000000..9c27f1db955 --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintList.hpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP +#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP + +#include "runtime/flags/jvmFlag.hpp" +#include "utilities/growableArray.hpp" + +/* + * Here we have a mechanism for extracting constraints (as custom functions) for flags, + * which otherwise can not be expressed via simple range check, specified in flag macro tables. + * + * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change. + * + * See runtime "runtime/flags/jvmFlagConstraintsCompiler.hpp", + * "runtime/flags/jvmFlagConstraintsGC.hpp" and + * "runtime/flags/jvmFlagConstraintsRuntime.hpp" for the functions themselves. + */ + +typedef JVMFlag::Error (*JVMFlagConstraintFunc_bool)(bool value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_int)(int value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_intx)(intx value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint)(uint value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_uintx)(uintx value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_size_t)(size_t value, bool verbose); +typedef JVMFlag::Error (*JVMFlagConstraintFunc_double)(double value, bool verbose); + +class JVMFlagConstraint : public CHeapObj { +public: + // During VM initialization, constraint validation will be done order of ConstraintType. + enum ConstraintType { + // Will be validated during argument processing (Arguments::parse_argument). + AtParse = 0, + // Will be validated inside Threads::create_vm(), right after Arguments::apply_ergo(). + AfterErgo = 1, + // Will be validated inside universe_init(), right after Metaspace::global_initialize(). + AfterMemoryInit = 2 + }; + +private: + const char* _name; + ConstraintType _validate_type; + +public: + // the "name" argument must be a string literal + JVMFlagConstraint(const char* name, ConstraintType type) { _name=name; _validate_type=type; }; + ~JVMFlagConstraint() {}; + const char* name() const { return _name; } + ConstraintType type() const { return _validate_type; } + virtual JVMFlag::Error apply(bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; + virtual JVMFlag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; }; +}; + +class JVMFlagConstraintList : public AllStatic { +private: + static GrowableArray* _constraints; + // Latest constraint validation type. + static JVMFlagConstraint::ConstraintType _validating_type; +public: + static void init(); + static int length() { return (_constraints != NULL) ? _constraints->length() : 0; } + static JVMFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; } + static JVMFlagConstraint* find(const char* name); + static JVMFlagConstraint* find_if_needs_check(const char* name); + static void add(JVMFlagConstraint* constraint) { _constraints->append(constraint); } + // True if 'AfterErgo' or later constraint functions are validated. + static bool validated_after_ergo() { return _validating_type >= JVMFlagConstraint::AfterErgo; }; + static bool check_constraints(JVMFlagConstraint::ConstraintType type); +}; + +#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTLIST_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp similarity index 80% rename from src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 13d8498aa5e..3055dfcd026 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -29,21 +29,22 @@ #include "runtime/os.hpp" #include "interpreter/invocationCounter.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintsCompiler.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintsCompiler.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "utilities/defaultStream.hpp" -Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose) { if ((value <= 1) && (Arguments::mode() == Arguments::_comp || Arguments::mode() == Arguments::_mixed)) { CommandLineError::print(verbose, "AliasLevel (" INTX_FORMAT ") is not " "compatible with -Xcomp or -Xmixed\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -62,7 +63,7 @@ Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) { * 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result, * the minimum number of compiler threads is 2. */ -Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; #if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI // case 1 @@ -85,37 +86,37 @@ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { "CICompilerCount (" INTX_FORMAT ") must be " "at least %d \n", value, min_number_of_compiler_threads); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { if (value < 0 || value > 512) { CommandLineError::print(verbose, "AllocatePrefetchDistance (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", AllocatePrefetchDistance, 512); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { if (AllocatePrefetchStyle == 3) { if (value % wordSize != 0) { CommandLineError::print(verbose, "AllocatePrefetchStepSize (" INTX_FORMAT ") must be multiple of %d\n", value, wordSize); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { +JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { intx max_value = max_intx; #if defined(SPARC) max_value = 1; @@ -126,26 +127,26 @@ Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "AllocatePrefetchInstr (" INTX_FORMAT ") must be " "between 0 and " INTX_FORMAT "\n", value, max_value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { if (value < 0 || value > INT_MAX >> InvocationCounter::count_shift) { CommandLineError::print(verbose, "CompileThreshold (" INTX_FORMAT ") " "must be between 0 and %d\n", value, INT_MAX >> InvocationCounter::count_shift); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { +JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { int backward_branch_limit; if (ProfileInterpreter) { if (OnStackReplacePercentage < InterpreterProfilePercentage) { @@ -153,7 +154,7 @@ Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { "OnStackReplacePercentage (" INTX_FORMAT ") must be " "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", OnStackReplacePercentage, InterpreterProfilePercentage); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } backward_branch_limit = ((CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100) @@ -167,14 +168,14 @@ Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { "CompileThreshold, InterpreterProfilePercentage, and/or OnStackReplacePercentage\n", (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100, INT_MAX >> InvocationCounter::count_shift); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } else { if (OnStackReplacePercentage < 0 ) { CommandLineError::print(verbose, "OnStackReplacePercentage (" INTX_FORMAT ") must be " "non-negative\n", OnStackReplacePercentage); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } backward_branch_limit = ((CompileThreshold * OnStackReplacePercentage) / 100) @@ -187,20 +188,20 @@ Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { "CompileThreshold and/or OnStackReplacePercentage\n", (CompileThreshold * OnStackReplacePercentage) / 100, INT_MAX >> InvocationCounter::count_shift); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) { CommandLineError::print(verbose, "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ") " "to align entry points\n", CodeCacheSegmentSize, CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (CodeCacheSegmentSize < sizeof(jdouble)) { @@ -208,7 +209,7 @@ Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " "at least " SIZE_FORMAT " to align constants\n", CodeCacheSegmentSize, sizeof(jdouble)); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #ifdef COMPILER2 @@ -218,14 +219,14 @@ Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ") " "to align inner loops\n", CodeCacheSegmentSize, OptoLoopAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { #ifdef SOLARIS if ((value < MinimumPriority || value > MaximumPriority) && (value != -1) && (value != -FXCriticalPriority)) { @@ -234,20 +235,20 @@ Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { "between %d and %d inclusively or -1 (means no change) " "or %d (special value for critical thread class/priority)\n", value, MinimumPriority, MaximumPriority, -FXCriticalPriority); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { +JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { #ifdef SPARC if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { CommandLineError::print(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "multiple of NOP size\n", CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif @@ -255,7 +256,7 @@ Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } if (CodeEntryAlignment < 16) { @@ -263,19 +264,19 @@ Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { "CodeEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", CodeEntryAlignment, 16); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { +JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "OptoLoopAlignment (" INTX_FORMAT ") " "must be a power of two\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // Relevant on ppc, s390, sparc. Will be optimized where @@ -285,64 +286,64 @@ Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { "OptoLoopAlignment (" INTX_FORMAT ") must be " "multiple of NOP size (%d)\n", value, relocInfo::addr_unit()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { if (value >= 4032) { CommandLineError::print(verbose, "ArraycopyDstPrefetchDistance (" UINTX_FORMAT ") must be" "between 0 and 4031\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { if (value >= 4032) { CommandLineError::print(verbose, "ArraycopySrcPrefetchDistance (" UINTX_FORMAT ") must be" "between 0 and 4031\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { +JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { for (int i = 0; i < 3; i++) { if (value % 10 > 2) { CommandLineError::print(verbose, "Invalid value (" UINTX_FORMAT ") " "in TypeProfileLevel at position %d\n", value, i); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } value = value / 10; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { +JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose) { if (value % BytesPerLong != 0) { - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } #ifdef COMPILER2 -Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { +JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { if (InteriorEntryAlignment > CodeEntryAlignment) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", InteriorEntryAlignment, CodeEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #ifdef SPARC @@ -350,7 +351,7 @@ Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "multiple of NOP size\n"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } #endif @@ -358,7 +359,7 @@ Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { CommandLineError::print(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " "a power of two\n", InteriorEntryAlignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } int minimum_alignment = 16; @@ -373,26 +374,26 @@ Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { "InteriorEntryAlignment (" INTX_FORMAT ") must be " "greater than or equal to %d\n", InteriorEntryAlignment, minimum_alignment); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } -Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { +JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { if (value < MaxNodeLimit * 2 / 100 || value > MaxNodeLimit * 40 / 100) { CommandLineError::print(verbose, "NodeLimitFudgeFactor must be between 2%% and 40%% " "of MaxNodeLimit (" INTX_FORMAT ")\n", MaxNodeLimit); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } #endif // COMPILER2 -Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { +JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { #if INCLUDE_RTM_OPT if (UseRTMLocking && !is_power_of_2(RTMTotalCountIncrRate)) { CommandLineError::print(verbose, @@ -403,5 +404,5 @@ Flag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose) { } #endif - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp new file mode 100644 index 00000000000..f18b1269ed1 --- /dev/null +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP +#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP + +#include "runtime/flags/jvmFlag.hpp" + +/* + * Here we have compiler arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +JVMFlag::Error AliasLevelConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CICompilerCountConstraintFunc(intx value, bool verbose); + +JVMFlag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); + +JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); + +JVMFlag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CompileThresholdConstraintFunc(intx value, bool verbose); + +JVMFlag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); + +JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); + +JVMFlag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); + +JVMFlag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); + +JVMFlag::Error InitArrayShortSizeConstraintFunc(intx value, bool verbose); + +#ifdef COMPILER2 +JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); + +JVMFlag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); +#endif + +JVMFlag::Error RTMTotalCountIncrRateConstraintFunc(int value, bool verbose); + +#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSCOMPILER_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp similarity index 77% rename from src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp index 55483983094..fdcb9bb193a 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp @@ -24,20 +24,21 @@ #include "precompiled.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintsRuntime.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintsRuntime.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/task.hpp" #include "utilities/defaultStream.hpp" -Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { +JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { if (!is_power_of_2(value)) { CommandLineError::print(verbose, "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "power of 2\n", value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } // In case page size is very small. if (value >= (intx)os::vm_page_size()) { @@ -45,99 +46,99 @@ Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) { "ObjectAlignmentInBytes (" INTX_FORMAT ") must be " "less than page size (" INTX_FORMAT ")\n", value, (intx)os::vm_page_size()); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } // Need to enforce the padding not to break the existing field alignments. // It is sufficient to check against the largest type size. -Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { +JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) { if ((value % BytesPerLong) != 0) { CommandLineError::print(verbose, "ContendedPaddingWidth (" INTX_FORMAT ") must be " "a multiple of %d\n", value, BytesPerLong); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose) { if (value > BiasedLockingBulkRevokeThreshold) { CommandLineError::print(verbose, "BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ") must be " "less than or equal to BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRevokeThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran) != 0) { CommandLineError::print(verbose, "BiasedLockingStartupDelay (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", value, PeriodicTask::interval_gran); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose) { if (value < BiasedLockingBulkRebiasThreshold) { CommandLineError::print(verbose, "BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ") must be " "greater than or equal to BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")\n", value, BiasedLockingBulkRebiasThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else if ((double)value/(double)BiasedLockingDecayTime > 0.1) { CommandLineError::print(verbose, "The ratio of BiasedLockingBulkRevokeThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " "less than or equal to 0.1\n", value, BiasedLockingBulkRebiasThreshold); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { +JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose) { if (BiasedLockingBulkRebiasThreshold/(double)value > 0.1) { CommandLineError::print(verbose, "The ratio of BiasedLockingBulkRebiasThreshold (" INTX_FORMAT ")" " to BiasedLockingDecayTime (" INTX_FORMAT ") must be " "less than or equal to 0.1\n", BiasedLockingBulkRebiasThreshold, value); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { +JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose) { if ((value % PeriodicTask::interval_gran != 0)) { CommandLineError::print(verbose, "PerfDataSamplingInterval (" INTX_FORMAT ") must be " "evenly divisible by PeriodicTask::interval_gran (" INTX_FORMAT ")\n", value, PeriodicTask::interval_gran); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } -Flag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { +JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose) { if (value) { if (!SafepointMechanism::supports_thread_local_poll()) { CommandLineError::print(verbose, "ThreadLocalHandshakes not yet supported on this platform\n"); - return Flag::VIOLATES_CONSTRAINT; + return JVMFlag::VIOLATES_CONSTRAINT; } } - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } diff --git a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp similarity index 60% rename from src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp rename to src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp index 52452846df2..8763b83fd37 100644 --- a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.hpp @@ -22,11 +22,10 @@ * */ -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP +#ifndef SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP +#define SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" +#include "runtime/flags/jvmFlag.hpp" /* * Here we have runtime arguments constraints functions, which are called automatically @@ -34,18 +33,18 @@ * an appropriate error value. */ -Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); +JVMFlag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose); -Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); +JVMFlag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose); -Flag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); -Flag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); -Flag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); -Flag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingBulkRebiasThresholdFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingStartupDelayFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingBulkRevokeThresholdFunc(intx value, bool verbose); +JVMFlag::Error BiasedLockingDecayTimeFunc(intx value, bool verbose); -Flag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); +JVMFlag::Error PerfDataSamplingIntervalFunc(intx value, bool verbose); -Flag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose); +JVMFlag::Error ThreadLocalHandshakesConstraintFunc(bool value, bool verbose); -#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */ +#endif /* SHARE_VM_RUNTIME_JVMFLAGCONSTRAINTSRUNTIME_HPP */ diff --git a/src/hotspot/share/runtime/commandLineFlagRangeList.cpp b/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp similarity index 75% rename from src/hotspot/share/runtime/commandLineFlagRangeList.cpp rename to src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp index a6973fc12cd..97b074e59b9 100644 --- a/src/hotspot/share/runtime/commandLineFlagRangeList.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagRangeList.cpp @@ -29,8 +29,9 @@ #include "gc/shared/referenceProcessor.hpp" #include "oops/markOop.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/globals_extension.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" @@ -46,29 +47,29 @@ void CommandLineError::print(bool verbose, const char* msg, ...) { } } -class CommandLineFlagRange_int : public CommandLineFlagRange { +class JVMFlagRange_int : public JVMFlagRange { int _min; int _max; const int* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_int(const char* name, const int* ptr, int min, int max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_int(const char* name, const int* ptr, int min, int max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_int(*_ptr, verbose); } - Flag::Error check_int(int value, bool verbose = true) { + JVMFlag::Error check_int(int value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "int %s=%d is outside the allowed range " "[ %d ... %d ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -77,28 +78,28 @@ public: } }; -class CommandLineFlagRange_intx : public CommandLineFlagRange { +class JVMFlagRange_intx : public JVMFlagRange { intx _min; intx _max; const intx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_intx(const char* name, const intx* ptr, intx min, intx max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_intx(const char* name, const intx* ptr, intx min, intx max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_intx(*_ptr, verbose); } - Flag::Error check_intx(intx value, bool verbose = true) { + JVMFlag::Error check_intx(intx value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "intx %s=" INTX_FORMAT " is outside the allowed range " "[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -107,29 +108,29 @@ public: } }; -class CommandLineFlagRange_uint : public CommandLineFlagRange { +class JVMFlagRange_uint : public JVMFlagRange { uint _min; uint _max; const uint* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_uint(const char* name, const uint* ptr, uint min, uint max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_uint(const char* name, const uint* ptr, uint min, uint max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_uint(*_ptr, verbose); } - Flag::Error check_uint(uint value, bool verbose = true) { + JVMFlag::Error check_uint(uint value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uint %s=%u is outside the allowed range " "[ %u ... %u ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -138,29 +139,29 @@ public: } }; -class CommandLineFlagRange_uintx : public CommandLineFlagRange { +class JVMFlagRange_uintx : public JVMFlagRange { uintx _min; uintx _max; const uintx* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_uintx(const char* name, const uintx* ptr, uintx min, uintx max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_uintx(const char* name, const uintx* ptr, uintx min, uintx max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_uintx(*_ptr, verbose); } - Flag::Error check_uintx(uintx value, bool verbose = true) { + JVMFlag::Error check_uintx(uintx value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uintx %s=" UINTX_FORMAT " is outside the allowed range " "[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -169,29 +170,29 @@ public: } }; -class CommandLineFlagRange_uint64_t : public CommandLineFlagRange { +class JVMFlagRange_uint64_t : public JVMFlagRange { uint64_t _min; uint64_t _max; const uint64_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_uint64_t(*_ptr, verbose); } - Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { + JVMFlag::Error check_uint64_t(uint64_t value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "uint64_t %s=" UINT64_FORMAT " is outside the allowed range " "[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -200,29 +201,29 @@ public: } }; -class CommandLineFlagRange_size_t : public CommandLineFlagRange { +class JVMFlagRange_size_t : public JVMFlagRange { size_t _min; size_t _max; const size_t* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_size_t(const char* name, const size_t* ptr, size_t min, size_t max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_size_t(const char* name, const size_t* ptr, size_t min, size_t max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_size_t(*_ptr, verbose); } - Flag::Error check_size_t(size_t value, bool verbose = true) { + JVMFlag::Error check_size_t(size_t value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "size_t %s=" SIZE_FORMAT " is outside the allowed range " "[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -231,29 +232,29 @@ public: } }; -class CommandLineFlagRange_double : public CommandLineFlagRange { +class JVMFlagRange_double : public JVMFlagRange { double _min; double _max; const double* _ptr; public: // the "name" argument must be a string literal - CommandLineFlagRange_double(const char* name, const double* ptr, double min, double max) - : CommandLineFlagRange(name), _min(min), _max(max), _ptr(ptr) {} + JVMFlagRange_double(const char* name, const double* ptr, double min, double max) + : JVMFlagRange(name), _min(min), _max(max), _ptr(ptr) {} - Flag::Error check(bool verbose = true) { + JVMFlag::Error check(bool verbose = true) { return check_double(*_ptr, verbose); } - Flag::Error check_double(double value, bool verbose = true) { + JVMFlag::Error check_double(double value, bool verbose = true) { if ((value < _min) || (value > _max)) { CommandLineError::print(verbose, "double %s=%f is outside the allowed range " "[ %f ... %f ]\n", name(), value, _min, _max); - return Flag::OUT_OF_BOUNDS; + return JVMFlag::OUT_OF_BOUNDS; } else { - return Flag::SUCCESS; + return JVMFlag::SUCCESS; } } @@ -277,27 +278,27 @@ void emit_range_uint64_t(const char* /*name*/, const uint64_t* /*value*/) { / void emit_range_size_t(const char* /*name*/, const size_t* /*value*/) { /* NOP */ } void emit_range_double(const char* /*name*/, const double* /*value*/) { /* NOP */ } -// CommandLineFlagRange emitting code functions if range arguments are provided +// JVMFlagRange emitting code functions if range arguments are provided void emit_range_int(const char* name, const int* ptr, int min, int max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_int(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_int(name, ptr, min, max)); } void emit_range_intx(const char* name, const intx* ptr, intx min, intx max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_intx(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_intx(name, ptr, min, max)); } void emit_range_uint(const char* name, const uint* ptr, uint min, uint max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_uint(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_uint(name, ptr, min, max)); } void emit_range_uintx(const char* name, const uintx* ptr, uintx min, uintx max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_uintx(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_uintx(name, ptr, min, max)); } void emit_range_uint64_t(const char* name, const uint64_t* ptr, uint64_t min, uint64_t max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_uint64_t(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_uint64_t(name, ptr, min, max)); } void emit_range_size_t(const char* name, const size_t* ptr, size_t min, size_t max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_size_t(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_size_t(name, ptr, min, max)); } void emit_range_double(const char* name, const double* ptr, double min, double max) { - CommandLineFlagRangeList::add(new CommandLineFlagRange_double(name, ptr, min, max)); + JVMFlagRangeList::add(new JVMFlagRange_double(name, ptr, min, max)); } // Generate code to call emit_range_xxx function @@ -328,12 +329,12 @@ void emit_range_double(const char* name, const double* ptr, double min, double m #define EMIT_RANGE_CHECK(a, b) , a, b #define INITIAL_RANGES_SIZE 379 -GrowableArray* CommandLineFlagRangeList::_ranges = NULL; +GrowableArray* JVMFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them -void CommandLineFlagRangeList::init(void) { +void JVMFlagRangeList::init(void) { - _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_RANGES_SIZE, true); + _ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_RANGES_SIZE, true); emit_range_no(NULL VM_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, EMIT_RANGE_PD_DEVELOPER_FLAG, @@ -403,10 +404,10 @@ void CommandLineFlagRangeList::init(void) { #endif // COMPILER2 } -CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) { - CommandLineFlagRange* found = NULL; +JVMFlagRange* JVMFlagRangeList::find(const char* name) { + JVMFlagRange* found = NULL; for (int i=0; iname(), name) == 0) { found = range; break; @@ -415,12 +416,12 @@ CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) { return found; } -void CommandLineFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); +void JVMFlagRangeList::print(outputStream* st, const char* name, RangeStrFunc default_range_str_func) { + JVMFlagRange* range = JVMFlagRangeList::find(name); if (range != NULL) { range->print(st); } else { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name); + JVMFlagConstraint* constraint = JVMFlagConstraintList::find(name); if (constraint != NULL) { assert(default_range_str_func!=NULL, "default_range_str_func must be provided"); st->print("%s", default_range_str_func()); @@ -430,12 +431,12 @@ void CommandLineFlagRangeList::print(outputStream* st, const char* name, RangeSt } } -bool CommandLineFlagRangeList::check_ranges() { +bool JVMFlagRangeList::check_ranges() { // Check ranges. bool status = true; for (int i=0; icheck(true) != Flag::SUCCESS) status = false; + JVMFlagRange* range = at(i); + if (range->check(true) != JVMFlag::SUCCESS) status = false; } return status; } diff --git a/src/hotspot/share/runtime/commandLineFlagRangeList.hpp b/src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp similarity index 56% rename from src/hotspot/share/runtime/commandLineFlagRangeList.hpp rename to src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp index 318973505a5..6fa23cea244 100644 --- a/src/hotspot/share/runtime/commandLineFlagRangeList.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagRangeList.hpp @@ -22,11 +22,11 @@ * */ -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP +#ifndef SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP +#define SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP #include "memory/metaspaceShared.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "utilities/growableArray.hpp" /* @@ -44,36 +44,36 @@ public: static void print(bool verbose, const char* msg, ...); }; -class CommandLineFlagRange : public CHeapObj { +class JVMFlagRange : public CHeapObj { private: const char* _name; public: // the "name" argument must be a string literal - CommandLineFlagRange(const char* name) { _name=name; } - ~CommandLineFlagRange() {} + JVMFlagRange(const char* name) { _name=name; } + ~JVMFlagRange() {} const char* name() { return _name; } - virtual Flag::Error check(bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } - virtual Flag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; } + virtual JVMFlag::Error check(bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } + virtual JVMFlag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return JVMFlag::ERR_OTHER; } virtual void print(outputStream* st) { ; } }; -class CommandLineFlagRangeList : public AllStatic { - static GrowableArray* _ranges; +class JVMFlagRangeList : public AllStatic { + static GrowableArray* _ranges; public: static void init(); static int length() { return (_ranges != NULL) ? _ranges->length() : 0; } - static CommandLineFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } - static CommandLineFlagRange* find(const char* name); - static void add(CommandLineFlagRange* range) { _ranges->append(range); } + static JVMFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; } + static JVMFlagRange* find(const char* name); + static void add(JVMFlagRange* range) { _ranges->append(range); } static void print(outputStream* st, const char* name, RangeStrFunc default_range_str_func); // Check the final values of all flags for ranges. static bool check_ranges(); }; -#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP +#endif // SHARE_VM_RUNTIME_JVMFLAGRANGELIST_HPP diff --git a/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp similarity index 76% rename from src/hotspot/share/runtime/commandLineFlagWriteableList.cpp rename to src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp index 214e614afc8..a80d21c0d34 100644 --- a/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/plab.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" #include "runtime/os.hpp" #ifdef COMPILER1 #include "c1/c1_globals.hpp" @@ -36,18 +36,18 @@ #include "jvmci/jvmci_globals.hpp" #endif -bool CommandLineFlagWriteable::is_writeable(void) { +bool JVMFlagWriteable::is_writeable(void) { return _writeable; } -void CommandLineFlagWriteable::mark_once(void) { +void JVMFlagWriteable::mark_once(void) { if (_type == Once) { _writeable = false; } } -void CommandLineFlagWriteable::mark_startup(void) { - if (_type == CommandLineFlagWriteable::CommandLineOnly) { +void JVMFlagWriteable::mark_startup(void) { + if (_type == JVMFlagWriteable::CommandLineOnly) { _writeable = false; } } @@ -67,30 +67,30 @@ void emit_writeable_uint64_t(const char* /*name*/) { /* NOP */ } void emit_writeable_size_t(const char* /*name*/) { /* NOP */ } void emit_writeable_double(const char* /*name*/) { /* NOP */ } -// CommandLineFlagWriteable emitting code functions if range arguments are provided -void emit_writeable_bool(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +// JVMFlagWriteable emitting code functions if range arguments are provided +void emit_writeable_bool(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_int(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_int(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_intx(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_intx(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_uint(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_uint(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_uintx(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_uintx(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_uint64_t(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_uint64_t(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_size_t(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_size_t(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } -void emit_writeable_double(const char* name, CommandLineFlagWriteable::WriteableType type) { - CommandLineFlagWriteableList::add(new CommandLineFlagWriteable(name, type)); +void emit_writeable_double(const char* name, JVMFlagWriteable::WriteableType type) { + JVMFlagWriteableList::add(new JVMFlagWriteable(name, type)); } // Generate code to call emit_writeable_xxx function @@ -108,14 +108,14 @@ void emit_writeable_double(const char* name, CommandLineFlagWriteable::Writeable #define EMIT_WRITEABLE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_writeable_##type(#name // Generate type argument to pass into emit_writeable_xxx functions -#define EMIT_WRITEABLE(a) , CommandLineFlagWriteable::a +#define EMIT_WRITEABLE(a) , JVMFlagWriteable::a #define INITIAL_WRITEABLES_SIZE 2 -GrowableArray* CommandLineFlagWriteableList::_controls = NULL; +GrowableArray* JVMFlagWriteableList::_controls = NULL; -void CommandLineFlagWriteableList::init(void) { +void JVMFlagWriteableList::init(void) { - _controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_WRITEABLES_SIZE, true); + _controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(INITIAL_WRITEABLES_SIZE, true); emit_writeable_no(NULL VM_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG, EMIT_WRITEABLE_PD_DEVELOPER_FLAG, @@ -185,10 +185,10 @@ void CommandLineFlagWriteableList::init(void) { #endif // COMPILER2 } -CommandLineFlagWriteable* CommandLineFlagWriteableList::find(const char* name) { - CommandLineFlagWriteable* found = NULL; +JVMFlagWriteable* JVMFlagWriteableList::find(const char* name) { + JVMFlagWriteable* found = NULL; for (int i=0; iname(), name) == 0) { found = writeable; break; @@ -197,9 +197,9 @@ CommandLineFlagWriteable* CommandLineFlagWriteableList::find(const char* name) { return found; } -void CommandLineFlagWriteableList::mark_startup(void) { +void JVMFlagWriteableList::mark_startup(void) { for (int i=0; imark_startup(); } } diff --git a/src/hotspot/share/runtime/commandLineFlagWriteableList.hpp b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp similarity index 70% rename from src/hotspot/share/runtime/commandLineFlagWriteableList.hpp rename to src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp index 84220851fb2..aca87e30f1f 100644 --- a/src/hotspot/share/runtime/commandLineFlagWriteableList.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagWriteableList.hpp @@ -22,13 +22,12 @@ * */ -#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP -#define SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP +#ifndef SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP +#define SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP -#include "runtime/globals.hpp" #include "utilities/growableArray.hpp" -class CommandLineFlagWriteable : public CHeapObj { +class JVMFlagWriteable : public CHeapObj { public: enum WriteableType { // can be set without any limits @@ -45,8 +44,8 @@ private: bool _startup_done; public: // the "name" argument must be a string literal - CommandLineFlagWriteable(const char* name, WriteableType type) { _name=name; _type=type; _writeable=true; _startup_done=false; } - ~CommandLineFlagWriteable() {} + JVMFlagWriteable(const char* name, WriteableType type) { _name=name; _type=type; _writeable=true; _startup_done=false; } + ~JVMFlagWriteable() {} const char* name() { return _name; } const WriteableType type() { return _type; } bool is_writeable(void); @@ -54,15 +53,15 @@ public: void mark_startup(void); }; -class CommandLineFlagWriteableList : public AllStatic { - static GrowableArray* _controls; +class JVMFlagWriteableList : public AllStatic { + static GrowableArray* _controls; public: static void init(); static int length() { return (_controls != NULL) ? _controls->length() : 0; } - static CommandLineFlagWriteable* at(int i) { return (_controls != NULL) ? _controls->at(i) : NULL; } - static CommandLineFlagWriteable* find(const char* name); - static void add(CommandLineFlagWriteable* range) { _controls->append(range); } + static JVMFlagWriteable* at(int i) { return (_controls != NULL) ? _controls->at(i) : NULL; } + static JVMFlagWriteable* find(const char* name); + static void add(JVMFlagWriteable* range) { _controls->append(range); } static void mark_startup(void); }; -#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGWRITEABLE_HPP +#endif // SHARE_VM_RUNTIME_JVMFLAGWRITEABLE_HPP diff --git a/src/hotspot/share/runtime/globals.cpp b/src/hotspot/share/runtime/globals.cpp index 16054f408b1..3ee7d90df44 100644 --- a/src/hotspot/share/runtime/globals.cpp +++ b/src/hotspot/share/runtime/globals.cpp @@ -29,9 +29,9 @@ #include "runtime/arguments.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "trace/tracing.hpp" @@ -85,1473 +85,3 @@ ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ IGNORE_WRITEABLE) MATERIALIZE_FLAGS_EXT - -#define DEFAULT_RANGE_STR_CHUNK_SIZE 64 -static char* create_range_str(const char *fmt, ...) { - static size_t string_length = DEFAULT_RANGE_STR_CHUNK_SIZE; - static char* range_string = NEW_C_HEAP_ARRAY(char, string_length, mtLogging); - - int size_needed = 0; - do { - va_list args; - va_start(args, fmt); - size_needed = jio_vsnprintf(range_string, string_length, fmt, args); - va_end(args); - - if (size_needed < 0) { - string_length += DEFAULT_RANGE_STR_CHUNK_SIZE; - range_string = REALLOC_C_HEAP_ARRAY(char, range_string, string_length, mtLogging); - guarantee(range_string != NULL, "create_range_str string should not be NULL"); - } - } while (size_needed < 0); - - return range_string; -} - -const char* Flag::get_int_default_range_str() { - return create_range_str("[ " INT32_FORMAT_W(-25) " ... " INT32_FORMAT_W(25) " ]", INT_MIN, INT_MAX); -} - -const char* Flag::get_uint_default_range_str() { - return create_range_str("[ " UINT32_FORMAT_W(-25) " ... " UINT32_FORMAT_W(25) " ]", 0, UINT_MAX); -} - -const char* Flag::get_intx_default_range_str() { - return create_range_str("[ " INTX_FORMAT_W(-25) " ... " INTX_FORMAT_W(25) " ]", min_intx, max_intx); -} - -const char* Flag::get_uintx_default_range_str() { - return create_range_str("[ " UINTX_FORMAT_W(-25) " ... " UINTX_FORMAT_W(25) " ]", 0, max_uintx); -} - -const char* Flag::get_uint64_t_default_range_str() { - return create_range_str("[ " UINT64_FORMAT_W(-25) " ... " UINT64_FORMAT_W(25) " ]", 0, uint64_t(max_juint)); -} - -const char* Flag::get_size_t_default_range_str() { - return create_range_str("[ " SIZE_FORMAT_W(-25) " ... " SIZE_FORMAT_W(25) " ]", 0, SIZE_MAX); -} - -const char* Flag::get_double_default_range_str() { - return create_range_str("[ %-25.3f ... %25.3f ]", DBL_MIN, DBL_MAX); -} - -static bool is_product_build() { -#ifdef PRODUCT - return true; -#else - return false; -#endif -} - -Flag::Error Flag::check_writable(bool changed) { - if (is_constant_in_binary()) { - fatal("flag is constant: %s", _name); - } - - Flag::Error error = Flag::SUCCESS; - if (changed) { - CommandLineFlagWriteable* writeable = CommandLineFlagWriteableList::find(_name); - if (writeable) { - if (writeable->is_writeable() == false) { - switch (writeable->type()) - { - case CommandLineFlagWriteable::Once: - error = Flag::SET_ONLY_ONCE; - jio_fprintf(defaultStream::error_stream(), "Error: %s may not be set more than once\n", _name); - break; - case CommandLineFlagWriteable::CommandLineOnly: - error = Flag::COMMAND_LINE_ONLY; - jio_fprintf(defaultStream::error_stream(), "Error: %s may be modified only from commad line\n", _name); - break; - default: - ShouldNotReachHere(); - break; - } - } - writeable->mark_once(); - } - } - return error; -} - -bool Flag::is_bool() const { - return strcmp(_type, "bool") == 0; -} - -bool Flag::get_bool() const { - return *((bool*) _addr); -} - -Flag::Error Flag::set_bool(bool value) { - Flag::Error error = check_writable(value!=get_bool()); - if (error == Flag::SUCCESS) { - *((bool*) _addr) = value; - } - return error; -} - -bool Flag::is_int() const { - return strcmp(_type, "int") == 0; -} - -int Flag::get_int() const { - return *((int*) _addr); -} - -Flag::Error Flag::set_int(int value) { - Flag::Error error = check_writable(value!=get_int()); - if (error == Flag::SUCCESS) { - *((int*) _addr) = value; - } - return error; -} - -bool Flag::is_uint() const { - return strcmp(_type, "uint") == 0; -} - -uint Flag::get_uint() const { - return *((uint*) _addr); -} - -Flag::Error Flag::set_uint(uint value) { - Flag::Error error = check_writable(value!=get_uint()); - if (error == Flag::SUCCESS) { - *((uint*) _addr) = value; - } - return error; -} - -bool Flag::is_intx() const { - return strcmp(_type, "intx") == 0; -} - -intx Flag::get_intx() const { - return *((intx*) _addr); -} - -Flag::Error Flag::set_intx(intx value) { - Flag::Error error = check_writable(value!=get_intx()); - if (error == Flag::SUCCESS) { - *((intx*) _addr) = value; - } - return error; -} - -bool Flag::is_uintx() const { - return strcmp(_type, "uintx") == 0; -} - -uintx Flag::get_uintx() const { - return *((uintx*) _addr); -} - -Flag::Error Flag::set_uintx(uintx value) { - Flag::Error error = check_writable(value!=get_uintx()); - if (error == Flag::SUCCESS) { - *((uintx*) _addr) = value; - } - return error; -} - -bool Flag::is_uint64_t() const { - return strcmp(_type, "uint64_t") == 0; -} - -uint64_t Flag::get_uint64_t() const { - return *((uint64_t*) _addr); -} - -Flag::Error Flag::set_uint64_t(uint64_t value) { - Flag::Error error = check_writable(value!=get_uint64_t()); - if (error == Flag::SUCCESS) { - *((uint64_t*) _addr) = value; - } - return error; -} - -bool Flag::is_size_t() const { - return strcmp(_type, "size_t") == 0; -} - -size_t Flag::get_size_t() const { - return *((size_t*) _addr); -} - -Flag::Error Flag::set_size_t(size_t value) { - Flag::Error error = check_writable(value!=get_size_t()); - if (error == Flag::SUCCESS) { - *((size_t*) _addr) = value; - } - return error; -} - -bool Flag::is_double() const { - return strcmp(_type, "double") == 0; -} - -double Flag::get_double() const { - return *((double*) _addr); -} - -Flag::Error Flag::set_double(double value) { - Flag::Error error = check_writable(value!=get_double()); - if (error == Flag::SUCCESS) { - *((double*) _addr) = value; - } - return error; -} - -bool Flag::is_ccstr() const { - return strcmp(_type, "ccstr") == 0 || strcmp(_type, "ccstrlist") == 0; -} - -bool Flag::ccstr_accumulates() const { - return strcmp(_type, "ccstrlist") == 0; -} - -ccstr Flag::get_ccstr() const { - return *((ccstr*) _addr); -} - -Flag::Error Flag::set_ccstr(ccstr value) { - Flag::Error error = check_writable(value!=get_ccstr()); - if (error == Flag::SUCCESS) { - *((ccstr*) _addr) = value; - } - return error; -} - - -Flag::Flags Flag::get_origin() { - return Flags(_flags & VALUE_ORIGIN_MASK); -} - -void Flag::set_origin(Flags origin) { - assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); - Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); - _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); -} - -bool Flag::is_default() { - return (get_origin() == DEFAULT); -} - -bool Flag::is_ergonomic() { - return (get_origin() == ERGONOMIC); -} - -bool Flag::is_command_line() { - return (_flags & ORIG_COMMAND_LINE) != 0; -} - -void Flag::set_command_line() { - _flags = Flags(_flags | ORIG_COMMAND_LINE); -} - -bool Flag::is_product() const { - return (_flags & KIND_PRODUCT) != 0; -} - -bool Flag::is_manageable() const { - return (_flags & KIND_MANAGEABLE) != 0; -} - -bool Flag::is_diagnostic() const { - return (_flags & KIND_DIAGNOSTIC) != 0; -} - -bool Flag::is_experimental() const { - return (_flags & KIND_EXPERIMENTAL) != 0; -} - -bool Flag::is_notproduct() const { - return (_flags & KIND_NOT_PRODUCT) != 0; -} - -bool Flag::is_develop() const { - return (_flags & KIND_DEVELOP) != 0; -} - -bool Flag::is_read_write() const { - return (_flags & KIND_READ_WRITE) != 0; -} - -bool Flag::is_commercial() const { - return (_flags & KIND_COMMERCIAL) != 0; -} - -/** - * Returns if this flag is a constant in the binary. Right now this is - * true for notproduct and develop flags in product builds. - */ -bool Flag::is_constant_in_binary() const { -#ifdef PRODUCT - return is_notproduct() || is_develop(); -#else - return false; -#endif -} - -bool Flag::is_unlocker() const { - return strcmp(_name, "UnlockDiagnosticVMOptions") == 0 || - strcmp(_name, "UnlockExperimentalVMOptions") == 0 || - is_unlocker_ext(); -} - -bool Flag::is_unlocked() const { - if (is_diagnostic()) { - return UnlockDiagnosticVMOptions; - } - if (is_experimental()) { - return UnlockExperimentalVMOptions; - } - return is_unlocked_ext(); -} - -void Flag::clear_diagnostic() { - assert(is_diagnostic(), "sanity"); - _flags = Flags(_flags & ~KIND_DIAGNOSTIC); - assert(!is_diagnostic(), "sanity"); -} - -// Get custom message for this locked flag, or NULL if -// none is available. Returns message type produced. -Flag::MsgType Flag::get_locked_message(char* buf, int buflen) const { - buf[0] = '\0'; - if (is_diagnostic() && !is_unlocked()) { - jio_snprintf(buf, buflen, - "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n" - "Error: The unlock option must precede '%s'.\n", - _name, _name); - return Flag::DIAGNOSTIC_FLAG_BUT_LOCKED; - } - if (is_experimental() && !is_unlocked()) { - jio_snprintf(buf, buflen, - "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n" - "Error: The unlock option must precede '%s'.\n", - _name, _name); - return Flag::EXPERIMENTAL_FLAG_BUT_LOCKED; - } - if (is_develop() && is_product_build()) { - jio_snprintf(buf, buflen, "Error: VM option '%s' is develop and is available only in debug version of VM.\n", - _name); - return Flag::DEVELOPER_FLAG_BUT_PRODUCT_BUILD; - } - if (is_notproduct() && is_product_build()) { - jio_snprintf(buf, buflen, "Error: VM option '%s' is notproduct and is available only in debug version of VM.\n", - _name); - return Flag::NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD; - } - return get_locked_message_ext(buf, buflen); -} - -bool Flag::is_writeable() const { - return is_manageable() || (is_product() && is_read_write()) || is_writeable_ext(); -} - -// All flags except "manageable" are assumed to be internal flags. -// Long term, we need to define a mechanism to specify which flags -// are external/stable and change this function accordingly. -bool Flag::is_external() const { - return is_manageable() || is_external_ext(); -} - -// Helper function for Flag::print_on(). -// Fills current line up to requested position. -// Should the current position already be past the requested position, -// one separator blank is enforced. -void fill_to_pos(outputStream* st, unsigned int req_pos) { - if ((unsigned int)st->position() < req_pos) { - st->fill_to(req_pos); // need to fill with blanks to reach req_pos - } else { - st->print(" "); // enforce blank separation. Previous field too long. - } -} - -void Flag::print_on(outputStream* st, bool withComments, bool printRanges) { - // Don't print notproduct and develop flags in a product build. - if (is_constant_in_binary()) { - return; - } - - if (!printRanges) { - // The command line options -XX:+PrintFlags* cause this function to be called - // for each existing flag to print information pertinent to this flag. The data - // is displayed in columnar form, with the following layout: - // col1 - data type, right-justified - // col2 - name, left-justified - // col3 - ' =' double-char, leading space to align with possible '+=' - // col4 - value left-justified - // col5 - kind right-justified - // col6 - origin left-justified - // col7 - comments left-justified - // - // The column widths are fixed. They are defined such that, for most cases, - // an eye-pleasing tabular output is created. - // - // Sample output: - // bool CMSScavengeBeforeRemark = false {product} {default} - // uintx CMSScheduleRemarkEdenPenetration = 50 {product} {default} - // size_t CMSScheduleRemarkEdenSizeThreshold = 2097152 {product} {default} - // uintx CMSScheduleRemarkSamplingRatio = 5 {product} {default} - // double CMSSmallCoalSurplusPercent = 1.050000 {product} {default} - // ccstr CompileCommandFile = MyFile.cmd {product} {command line} - // ccstrlist CompileOnly = Method1 - // CompileOnly += Method2 {product} {command line} - // | | | | | | | - // | | | | | | +-- col7 - // | | | | | +-- col6 - // | | | | +-- col5 - // | | | +-- col4 - // | | +-- col3 - // | +-- col2 - // +-- col1 - - const unsigned int col_spacing = 1; - const unsigned int col1_pos = 0; - const unsigned int col1_width = 9; - const unsigned int col2_pos = col1_pos + col1_width + col_spacing; - const unsigned int col2_width = 39; - const unsigned int col3_pos = col2_pos + col2_width + col_spacing; - const unsigned int col3_width = 2; - const unsigned int col4_pos = col3_pos + col3_width + col_spacing; - const unsigned int col4_width = 30; - const unsigned int col5_pos = col4_pos + col4_width + col_spacing; - const unsigned int col5_width = 20; - const unsigned int col6_pos = col5_pos + col5_width + col_spacing; - const unsigned int col6_width = 15; - const unsigned int col7_pos = col6_pos + col6_width + col_spacing; - const unsigned int col7_width = 1; - - st->fill_to(col1_pos); - st->print("%*s", col1_width, _type); // right-justified, therefore width is required. - - fill_to_pos(st, col2_pos); - st->print("%s", _name); - - fill_to_pos(st, col3_pos); - st->print(" ="); // use " =" for proper alignment with multiline ccstr output. - - fill_to_pos(st, col4_pos); - if (is_bool()) { - st->print("%s", get_bool() ? "true" : "false"); - } else if (is_int()) { - st->print("%d", get_int()); - } else if (is_uint()) { - st->print("%u", get_uint()); - } else if (is_intx()) { - st->print(INTX_FORMAT, get_intx()); - } else if (is_uintx()) { - st->print(UINTX_FORMAT, get_uintx()); - } else if (is_uint64_t()) { - st->print(UINT64_FORMAT, get_uint64_t()); - } else if (is_size_t()) { - st->print(SIZE_FORMAT, get_size_t()); - } else if (is_double()) { - st->print("%f", get_double()); - } else if (is_ccstr()) { - // Honor characters in ccstr: print multiple lines. - const char* cp = get_ccstr(); - if (cp != NULL) { - const char* eol; - while ((eol = strchr(cp, '\n')) != NULL) { - size_t llen = pointer_delta(eol, cp, sizeof(char)); - st->print("%.*s", (int)llen, cp); - st->cr(); - cp = eol+1; - fill_to_pos(st, col2_pos); - st->print("%s", _name); - fill_to_pos(st, col3_pos); - st->print("+="); - fill_to_pos(st, col4_pos); - } - st->print("%s", cp); - } - } else { - st->print("unhandled type %s", _type); - st->cr(); - return; - } - - fill_to_pos(st, col5_pos); - print_kind(st, col5_width); - - fill_to_pos(st, col6_pos); - print_origin(st, col6_width); - -#ifndef PRODUCT - if (withComments) { - fill_to_pos(st, col7_pos); - st->print("%s", _doc); - } -#endif - st->cr(); - } else if (!is_bool() && !is_ccstr()) { - // The command line options -XX:+PrintFlags* cause this function to be called - // for each existing flag to print information pertinent to this flag. The data - // is displayed in columnar form, with the following layout: - // col1 - data type, right-justified - // col2 - name, left-justified - // col4 - range [ min ... max] - // col5 - kind right-justified - // col6 - origin left-justified - // col7 - comments left-justified - // - // The column widths are fixed. They are defined such that, for most cases, - // an eye-pleasing tabular output is created. - // - // Sample output: - // intx MinPassesBeforeFlush [ 0 ... 9223372036854775807 ] {diagnostic} {default} - // uintx MinRAMFraction [ 1 ... 18446744073709551615 ] {product} {default} - // double MinRAMPercentage [ 0.000 ... 100.000 ] {product} {default} - // uintx MinSurvivorRatio [ 3 ... 18446744073709551615 ] {product} {default} - // size_t MinTLABSize [ 1 ... 9223372036854775807 ] {product} {default} - // intx MonitorBound [ 0 ... 2147483647 ] {product} {default} - // | | | | | | - // | | | | | +-- col7 - // | | | | +-- col6 - // | | | +-- col5 - // | | +-- col4 - // | +-- col2 - // +-- col1 - - const unsigned int col_spacing = 1; - const unsigned int col1_pos = 0; - const unsigned int col1_width = 9; - const unsigned int col2_pos = col1_pos + col1_width + col_spacing; - const unsigned int col2_width = 49; - const unsigned int col3_pos = col2_pos + col2_width + col_spacing; - const unsigned int col3_width = 0; - const unsigned int col4_pos = col3_pos + col3_width + col_spacing; - const unsigned int col4_width = 60; - const unsigned int col5_pos = col4_pos + col4_width + col_spacing; - const unsigned int col5_width = 35; - const unsigned int col6_pos = col5_pos + col5_width + col_spacing; - const unsigned int col6_width = 15; - const unsigned int col7_pos = col6_pos + col6_width + col_spacing; - const unsigned int col7_width = 1; - - st->fill_to(col1_pos); - st->print("%*s", col1_width, _type); // right-justified, therefore width is required. - - fill_to_pos(st, col2_pos); - st->print("%s", _name); - - fill_to_pos(st, col4_pos); - RangeStrFunc func = NULL; - if (is_int()) { - func = Flag::get_int_default_range_str; - } else if (is_uint()) { - func = Flag::get_uint_default_range_str; - } else if (is_intx()) { - func = Flag::get_intx_default_range_str; - } else if (is_uintx()) { - func = Flag::get_uintx_default_range_str; - } else if (is_uint64_t()) { - func = Flag::get_uint64_t_default_range_str; - } else if (is_size_t()) { - func = Flag::get_size_t_default_range_str; - } else if (is_double()) { - func = Flag::get_double_default_range_str; - } else { - st->print("unhandled type %s", _type); - st->cr(); - return; - } - CommandLineFlagRangeList::print(st, _name, func); - - fill_to_pos(st, col5_pos); - print_kind(st, col5_width); - - fill_to_pos(st, col6_pos); - print_origin(st, col6_width); - -#ifndef PRODUCT - if (withComments) { - fill_to_pos(st, col7_pos); - st->print("%s", _doc); - } -#endif - st->cr(); - } -} - -void Flag::print_kind(outputStream* st, unsigned int width) { - struct Data { - int flag; - const char* name; - }; - - Data data[] = { - { KIND_JVMCI, "JVMCI" }, - { KIND_C1, "C1" }, - { KIND_C2, "C2" }, - { KIND_ARCH, "ARCH" }, - { KIND_PLATFORM_DEPENDENT, "pd" }, - { KIND_PRODUCT, "product" }, - { KIND_MANAGEABLE, "manageable" }, - { KIND_DIAGNOSTIC, "diagnostic" }, - { KIND_EXPERIMENTAL, "experimental" }, - { KIND_COMMERCIAL, "commercial" }, - { KIND_NOT_PRODUCT, "notproduct" }, - { KIND_DEVELOP, "develop" }, - { KIND_LP64_PRODUCT, "lp64_product" }, - { KIND_READ_WRITE, "rw" }, - { -1, "" } - }; - - if ((_flags & KIND_MASK) != 0) { - bool is_first = true; - const size_t buffer_size = 64; - size_t buffer_used = 0; - char kind[buffer_size]; - - jio_snprintf(kind, buffer_size, "{"); - buffer_used++; - for (int i = 0; data[i].flag != -1; i++) { - Data d = data[i]; - if ((_flags & d.flag) != 0) { - if (is_first) { - is_first = false; - } else { - assert(buffer_used + 1 < buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, " "); - buffer_used++; - } - size_t length = strlen(d.name); - assert(buffer_used + length < buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "%s", d.name); - buffer_used += length; - } - } - assert(buffer_used + 2 <= buffer_size, "Too small buffer"); - jio_snprintf(kind + buffer_used, buffer_size - buffer_used, "}"); - st->print("%*s", width, kind); - } -} - -void Flag::print_origin(outputStream* st, unsigned int width) { - int origin = _flags & VALUE_ORIGIN_MASK; - st->print("{"); - switch(origin) { - case DEFAULT: - st->print("default"); break; - case COMMAND_LINE: - st->print("command line"); break; - case ENVIRON_VAR: - st->print("environment"); break; - case CONFIG_FILE: - st->print("config file"); break; - case MANAGEMENT: - st->print("management"); break; - case ERGONOMIC: - if (_flags & ORIG_COMMAND_LINE) { - st->print("command line, "); - } - st->print("ergonomic"); break; - case ATTACH_ON_DEMAND: - st->print("attach"); break; - case INTERNAL: - st->print("internal"); break; - } - st->print("}"); -} - -void Flag::print_as_flag(outputStream* st) { - if (is_bool()) { - st->print("-XX:%s%s", get_bool() ? "+" : "-", _name); - } else if (is_int()) { - st->print("-XX:%s=%d", _name, get_int()); - } else if (is_uint()) { - st->print("-XX:%s=%u", _name, get_uint()); - } else if (is_intx()) { - st->print("-XX:%s=" INTX_FORMAT, _name, get_intx()); - } else if (is_uintx()) { - st->print("-XX:%s=" UINTX_FORMAT, _name, get_uintx()); - } else if (is_uint64_t()) { - st->print("-XX:%s=" UINT64_FORMAT, _name, get_uint64_t()); - } else if (is_size_t()) { - st->print("-XX:%s=" SIZE_FORMAT, _name, get_size_t()); - } else if (is_double()) { - st->print("-XX:%s=%f", _name, get_double()); - } else if (is_ccstr()) { - st->print("-XX:%s=", _name); - const char* cp = get_ccstr(); - if (cp != NULL) { - // Need to turn embedded '\n's back into separate arguments - // Not so efficient to print one character at a time, - // but the choice is to do the transformation to a buffer - // and print that. And this need not be efficient. - for (; *cp != '\0'; cp += 1) { - switch (*cp) { - default: - st->print("%c", *cp); - break; - case '\n': - st->print(" -XX:%s=", _name); - break; - } - } - } - } else { - ShouldNotReachHere(); - } -} - -const char* Flag::flag_error_str(Flag::Error error) { - switch (error) { - case Flag::MISSING_NAME: return "MISSING_NAME"; - case Flag::MISSING_VALUE: return "MISSING_VALUE"; - case Flag::NON_WRITABLE: return "NON_WRITABLE"; - case Flag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS"; - case Flag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT"; - case Flag::INVALID_FLAG: return "INVALID_FLAG"; - case Flag::ERR_OTHER: return "ERR_OTHER"; - case Flag::SUCCESS: return "SUCCESS"; - default: ShouldNotReachHere(); return "NULL"; - } -} - -// 4991491 do not "optimize out" the was_set false values: omitting them -// tickles a Microsoft compiler bug causing flagTable to be malformed - -#define RUNTIME_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT) }, -#define RUNTIME_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC) }, -#define RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_EXPERIMENTAL) }, -#define RUNTIME_MANAGEABLE_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_MANAGEABLE) }, -#define RUNTIME_PRODUCT_RW_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_PRODUCT | Flag::KIND_READ_WRITE) }, -#define RUNTIME_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP) }, -#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, - -#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT) }, -#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC) }, -#define JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_EXPERIMENTAL) }, -#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP) }, -#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_NOT_PRODUCT) }, - -#ifdef _LP64 -#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, -#else -#define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ -#endif // _LP64 - -#define C1_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT) }, -#define C1_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C1_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC) }, -#define C1_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C1_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP) }, -#define C1_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C1_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_NOT_PRODUCT) }, - -#define C2_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT) }, -#define C2_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C2_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC) }, -#define C2_PD_DIAGNOSTIC_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DIAGNOSTIC | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C2_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_EXPERIMENTAL) }, -#define C2_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP) }, -#define C2_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define C2_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | Flag::KIND_NOT_PRODUCT) }, - -#define ARCH_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_PRODUCT) }, -#define ARCH_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DIAGNOSTIC) }, -#define ARCH_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_EXPERIMENTAL) }, -#define ARCH_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_DEVELOP) }, -#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) }, - -static Flag flagTable[] = { - VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PRODUCT_FLAG_STRUCT, \ - RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ - RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \ - RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ - RUNTIME_MANAGEABLE_FLAG_STRUCT, \ - RUNTIME_PRODUCT_RW_FLAG_STRUCT, \ - RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) - - RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PD_DEVELOP_FLAG_STRUCT, \ - RUNTIME_PRODUCT_FLAG_STRUCT, \ - RUNTIME_PD_PRODUCT_FLAG_STRUCT, \ - RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \ - RUNTIME_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#if INCLUDE_JVMCI - JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ - JVMCI_PD_DEVELOP_FLAG_STRUCT, \ - JVMCI_PRODUCT_FLAG_STRUCT, \ - JVMCI_PD_PRODUCT_FLAG_STRUCT, \ - JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ - JVMCI_PD_DIAGNOSTIC_FLAG_STRUCT, \ - JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ - JVMCI_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // INCLUDE_JVMCI -#ifdef COMPILER1 - C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ - C1_PD_DEVELOP_FLAG_STRUCT, \ - C1_PRODUCT_FLAG_STRUCT, \ - C1_PD_PRODUCT_FLAG_STRUCT, \ - C1_DIAGNOSTIC_FLAG_STRUCT, \ - C1_PD_DIAGNOSTIC_FLAG_STRUCT, \ - C1_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // COMPILER1 -#ifdef COMPILER2 - C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \ - C2_PD_DEVELOP_FLAG_STRUCT, \ - C2_PRODUCT_FLAG_STRUCT, \ - C2_PD_PRODUCT_FLAG_STRUCT, \ - C2_DIAGNOSTIC_FLAG_STRUCT, \ - C2_PD_DIAGNOSTIC_FLAG_STRUCT, \ - C2_EXPERIMENTAL_FLAG_STRUCT, \ - C2_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) -#endif // COMPILER2 - ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \ - ARCH_PRODUCT_FLAG_STRUCT, \ - ARCH_DIAGNOSTIC_FLAG_STRUCT, \ - ARCH_EXPERIMENTAL_FLAG_STRUCT, \ - ARCH_NOTPRODUCT_FLAG_STRUCT, \ - IGNORE_RANGE, \ - IGNORE_CONSTRAINT, \ - IGNORE_WRITEABLE) - FLAGTABLE_EXT - {0, NULL, NULL} -}; - -Flag* Flag::flags = flagTable; -size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag)); - -inline bool str_equal(const char* s, size_t s_len, const char* q, size_t q_len) { - if (s_len != q_len) return false; - return memcmp(s, q, q_len) == 0; -} - -// Search the flag table for a named flag -Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) { - for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { - if (str_equal(current->_name, current->get_name_length(), name, length)) { - // Found a matching entry. - // Don't report notproduct and develop flags in product builds. - if (current->is_constant_in_binary()) { - return (return_flag ? current : NULL); - } - // Report locked flags only if allowed. - if (!(current->is_unlocked() || current->is_unlocker())) { - if (!allow_locked) { - // disable use of locked flags, e.g. diagnostic, experimental, - // commercial... until they are explicitly unlocked - return NULL; - } - } - return current; - } - } - // Flag name is not in the flag table - return NULL; -} - -// Get or compute the flag name length -size_t Flag::get_name_length() { - if (_name_len == 0) { - _name_len = strlen(_name); - } - return _name_len; -} - -Flag* Flag::fuzzy_match(const char* name, size_t length, bool allow_locked) { - float VMOptionsFuzzyMatchSimilarity = 0.7f; - Flag* match = NULL; - float score; - float max_score = -1; - - for (Flag* current = &flagTable[0]; current->_name != NULL; current++) { - score = StringUtils::similarity(current->_name, strlen(current->_name), name, length); - if (score > max_score) { - max_score = score; - match = current; - } - } - - if (!(match->is_unlocked() || match->is_unlocker())) { - if (!allow_locked) { - return NULL; - } - } - - if (max_score < VMOptionsFuzzyMatchSimilarity) { - return NULL; - } - - return match; -} - -// Returns the address of the index'th element -static Flag* address_of_flag(CommandLineFlagWithType flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - return &Flag::flags[flag]; -} - -bool CommandLineFlagsEx::is_default(CommandLineFlag flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - Flag* f = &Flag::flags[flag]; - return f->is_default(); -} - -bool CommandLineFlagsEx::is_ergo(CommandLineFlag flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - Flag* f = &Flag::flags[flag]; - return f->is_ergonomic(); -} - -bool CommandLineFlagsEx::is_cmdline(CommandLineFlag flag) { - assert((size_t)flag < Flag::numFlags, "bad command line flag index"); - Flag* f = &Flag::flags[flag]; - return f->is_command_line(); -} - -bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) { - Flag* result = Flag::find_flag((char*)name, strlen(name)); - if (result == NULL) return false; - *value = result->is_command_line(); - return true; -} - -void CommandLineFlagsEx::setOnCmdLine(CommandLineFlagWithType flag) { - Flag* faddr = address_of_flag(flag); - assert(faddr != NULL, "Unknown flag"); - faddr->set_command_line(); -} - -template -static void trace_flag_changed(const char* name, const T old_value, const T new_value, const Flag::Flags origin) { - E e; - e.set_name(name); - e.set_oldValue(old_value); - e.set_newValue(new_value); - e.set_origin(origin); - e.commit(); -} - -static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_bool(new_value, verbose); - } - return status; -} - -Flag::Error CommandLineFlags::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_bool()) return Flag::WRONG_FORMAT; - *value = result->get_bool(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::boolAtPut(Flag* flag, bool* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_bool()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_bool(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - bool old_value = flag->get_bool(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_bool(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return boolAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type"); - return CommandLineFlags::boolAtPut(faddr, &value, origin); -} - -static Flag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_int(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_int(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_int()) return Flag::WRONG_FORMAT; - *value = result->get_int(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::intAtPut(Flag* flag, int* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_int()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_int(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - int old_value = flag->get_int(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_int(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return intAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_int(), "wrong flag type"); - return CommandLineFlags::intAtPut(faddr, &value, origin); -} - -static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uint(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uint(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_uint()) return Flag::WRONG_FORMAT; - *value = result->get_uint(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::uintAtPut(Flag* flag, uint* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_uint()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_uint(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - uint old_value = flag->get_uint(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return uintAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type"); - return CommandLineFlags::uintAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_intx()) return Flag::WRONG_FORMAT; - *value = result->get_intx(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_intx(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_intx(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::intxAtPut(Flag* flag, intx* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_intx()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_intx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - intx old_value = flag->get_intx(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_intx(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return intxAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type"); - return CommandLineFlags::intxAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_uintx()) return Flag::WRONG_FORMAT; - *value = result->get_uintx(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uintx(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uintx(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_uintx()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_uintx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - uintx old_value = flag->get_uintx(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uintx(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return uintxAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type"); - return CommandLineFlags::uintxAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_uint64_t()) return Flag::WRONG_FORMAT; - *value = result->get_uint64_t(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_uint64_t(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_uint64_t(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_uint64_t()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - uint64_t old_value = flag->get_uint64_t(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_uint64_t(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return uint64_tAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); - return CommandLineFlags::uint64_tAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_size_t()) return Flag::WRONG_FORMAT; - *value = result->get_size_t(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_size_t(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_size_t(new_value, verbose); - } - } - return status; -} - - -Flag::Error CommandLineFlags::size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_size_t()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_size_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - size_t old_value = flag->get_size_t(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_size_t(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return size_tAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type"); - return CommandLineFlags::size_tAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_double()) return Flag::WRONG_FORMAT; - *value = result->get_double(); - return Flag::SUCCESS; -} - -static Flag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose) { - Flag::Error status = Flag::SUCCESS; - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); - if (range != NULL) { - status = range->check_double(new_value, verbose); - } - if (status == Flag::SUCCESS) { - CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name); - if (constraint != NULL) { - status = constraint->apply_double(new_value, verbose); - } - } - return status; -} - -Flag::Error CommandLineFlags::doubleAtPut(Flag* flag, double* value, Flag::Flags origin) { - const char* name; - if (flag == NULL) return Flag::INVALID_FLAG; - if (!flag->is_double()) return Flag::WRONG_FORMAT; - name = flag->_name; - Flag::Error check = apply_constraint_and_check_range_double(name, *value, !CommandLineFlagConstraintList::validated_after_ergo()); - if (check != Flag::SUCCESS) return check; - double old_value = flag->get_double(); - trace_flag_changed(name, old_value, *value, origin); - check = flag->set_double(*value); - *value = old_value; - flag->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - return doubleAtPut(result, value, origin); -} - -Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_double(), "wrong flag type"); - return CommandLineFlags::doubleAtPut(faddr, &value, origin); -} - -Flag::Error CommandLineFlags::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) { - Flag* result = Flag::find_flag(name, len, allow_locked, return_flag); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_ccstr()) return Flag::WRONG_FORMAT; - *value = result->get_ccstr(); - return Flag::SUCCESS; -} - -Flag::Error CommandLineFlags::ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin) { - Flag* result = Flag::find_flag(name, len); - if (result == NULL) return Flag::INVALID_FLAG; - if (!result->is_ccstr()) return Flag::WRONG_FORMAT; - ccstr old_value = result->get_ccstr(); - trace_flag_changed(name, old_value, *value, origin); - char* new_value = NULL; - if (*value != NULL) { - new_value = os::strdup_check_oom(*value); - } - Flag::Error check = result->set_ccstr(new_value); - if (result->is_default() && old_value != NULL) { - // Prior value is NOT heap allocated, but was a literal constant. - old_value = os::strdup_check_oom(old_value); - } - *value = old_value; - result->set_origin(origin); - return check; -} - -Flag::Error CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) { - Flag* faddr = address_of_flag(flag); - guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); - ccstr old_value = faddr->get_ccstr(); - trace_flag_changed(faddr->_name, old_value, value, origin); - char* new_value = os::strdup_check_oom(value); - Flag::Error check = faddr->set_ccstr(new_value); - if (!faddr->is_default() && old_value != NULL) { - // Prior value is heap allocated so free it. - FREE_C_HEAP_ARRAY(char, old_value); - } - faddr->set_origin(origin); - return check; -} - -extern "C" { - static int compare_flags(const void* void_a, const void* void_b) { - return strcmp((*((Flag**) void_a))->_name, (*((Flag**) void_b))->_name); - } -} - -void CommandLineFlags::printSetFlags(outputStream* out) { - // Print which flags were set on the command line - // note: this method is called before the thread structure is in place - // which means resource allocation cannot be used. - - // The last entry is the null entry. - const size_t length = Flag::numFlags - 1; - - // Sort - Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments); - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(Flag*), compare_flags); - - // Print - for (size_t i = 0; i < length; i++) { - if (array[i]->get_origin() /* naked field! */) { - array[i]->print_as_flag(out); - out->print(" "); - } - } - out->cr(); - FREE_C_HEAP_ARRAY(Flag*, array); -} - -#ifndef PRODUCT - -void CommandLineFlags::verify() { - assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict"); -} - -#endif // PRODUCT - -void CommandLineFlags::printFlags(outputStream* out, bool withComments, bool printRanges) { - // Print the flags sorted by name - // note: this method is called before the thread structure is in place - // which means resource allocation cannot be used. - - // The last entry is the null entry. - const size_t length = Flag::numFlags - 1; - - // Sort - Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtArguments); - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(Flag*), compare_flags); - - // Print - if (!printRanges) { - out->print_cr("[Global flags]"); - } else { - out->print_cr("[Global flags ranges]"); - } - - for (size_t i = 0; i < length; i++) { - if (array[i]->is_unlocked()) { - array[i]->print_on(out, withComments, printRanges); - } - } - FREE_C_HEAP_ARRAY(Flag*, array); -} diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 16b7eb1a3ea..1e03437ea4c 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -108,349 +108,6 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); #endif // no compilers -// string type aliases used only in this file -typedef const char* ccstr; -typedef const char* ccstrlist; // represents string arguments which accumulate - -// function type that will construct default range string -typedef const char* (*RangeStrFunc)(void); - -struct Flag { - enum Flags { - // latest value origin - DEFAULT = 0, - COMMAND_LINE = 1, - ENVIRON_VAR = 2, - CONFIG_FILE = 3, - MANAGEMENT = 4, - ERGONOMIC = 5, - ATTACH_ON_DEMAND = 6, - INTERNAL = 7, - - LAST_VALUE_ORIGIN = INTERNAL, - VALUE_ORIGIN_BITS = 4, - VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), - - // flag kind - KIND_PRODUCT = 1 << 4, - KIND_MANAGEABLE = 1 << 5, - KIND_DIAGNOSTIC = 1 << 6, - KIND_EXPERIMENTAL = 1 << 7, - KIND_NOT_PRODUCT = 1 << 8, - KIND_DEVELOP = 1 << 9, - KIND_PLATFORM_DEPENDENT = 1 << 10, - KIND_READ_WRITE = 1 << 11, - KIND_C1 = 1 << 12, - KIND_C2 = 1 << 13, - KIND_ARCH = 1 << 14, - KIND_LP64_PRODUCT = 1 << 15, - KIND_COMMERCIAL = 1 << 16, - KIND_JVMCI = 1 << 17, - - // set this bit if the flag was set on the command line - ORIG_COMMAND_LINE = 1 << 18, - - KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) - }; - - enum Error { - // no error - SUCCESS = 0, - // flag name is missing - MISSING_NAME, - // flag value is missing - MISSING_VALUE, - // error parsing the textual form of the value - WRONG_FORMAT, - // flag is not writable - NON_WRITABLE, - // flag value is outside of its bounds - OUT_OF_BOUNDS, - // flag value violates its constraint - VIOLATES_CONSTRAINT, - // there is no flag with the given name - INVALID_FLAG, - // the flag can only be set only on command line during invocation of the VM - COMMAND_LINE_ONLY, - // the flag may only be set once - SET_ONLY_ONCE, - // the flag is not writable in this combination of product/debug build - CONSTANT, - // other, unspecified error related to setting the flag - ERR_OTHER - }; - - enum MsgType { - NONE = 0, - DIAGNOSTIC_FLAG_BUT_LOCKED, - EXPERIMENTAL_FLAG_BUT_LOCKED, - DEVELOPER_FLAG_BUT_PRODUCT_BUILD, - NOTPRODUCT_FLAG_BUT_PRODUCT_BUILD, - COMMERCIAL_FLAG_BUT_DISABLED, - COMMERCIAL_FLAG_BUT_LOCKED - }; - - const char* _type; - const char* _name; - void* _addr; - NOT_PRODUCT(const char* _doc;) - Flags _flags; - size_t _name_len; - - // points to all Flags static array - static Flag* flags; - - // number of flags - static size_t numFlags; - - static Flag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); }; - static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false); - static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false); - - static const char* get_int_default_range_str(); - static const char* get_uint_default_range_str(); - static const char* get_intx_default_range_str(); - static const char* get_uintx_default_range_str(); - static const char* get_uint64_t_default_range_str(); - static const char* get_size_t_default_range_str(); - static const char* get_double_default_range_str(); - - Flag::Error check_writable(bool changed); - - bool is_bool() const; - bool get_bool() const; - Flag::Error set_bool(bool value); - - bool is_int() const; - int get_int() const; - Flag::Error set_int(int value); - - bool is_uint() const; - uint get_uint() const; - Flag::Error set_uint(uint value); - - bool is_intx() const; - intx get_intx() const; - Flag::Error set_intx(intx value); - - bool is_uintx() const; - uintx get_uintx() const; - Flag::Error set_uintx(uintx value); - - bool is_uint64_t() const; - uint64_t get_uint64_t() const; - Flag::Error set_uint64_t(uint64_t value); - - bool is_size_t() const; - size_t get_size_t() const; - Flag::Error set_size_t(size_t value); - - bool is_double() const; - double get_double() const; - Flag::Error set_double(double value); - - bool is_ccstr() const; - bool ccstr_accumulates() const; - ccstr get_ccstr() const; - Flag::Error set_ccstr(ccstr value); - - Flags get_origin(); - void set_origin(Flags origin); - - size_t get_name_length(); - - bool is_default(); - bool is_ergonomic(); - bool is_command_line(); - void set_command_line(); - - bool is_product() const; - bool is_manageable() const; - bool is_diagnostic() const; - bool is_experimental() const; - bool is_notproduct() const; - bool is_develop() const; - bool is_read_write() const; - bool is_commercial() const; - - bool is_constant_in_binary() const; - - bool is_unlocker() const; - bool is_unlocked() const; - bool is_writeable() const; - bool is_external() const; - - bool is_unlocker_ext() const; - bool is_unlocked_ext() const; - bool is_writeable_ext() const; - bool is_external_ext() const; - - void clear_diagnostic(); - - Flag::MsgType get_locked_message(char*, int) const; - Flag::MsgType get_locked_message_ext(char*, int) const; - - // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges - void print_on(outputStream* st, bool withComments = false, bool printRanges = false); - void print_kind(outputStream* st, unsigned int width); - void print_origin(outputStream* st, unsigned int width); - void print_as_flag(outputStream* st); - - static const char* flag_error_str(Flag::Error error); -}; - -// debug flags control various aspects of the VM and are global accessible - -// use FlagSetting to temporarily change some debug flag -// e.g. FlagSetting fs(DebugThisAndThat, true); -// restored to previous value upon leaving scope -class FlagSetting { - bool val; - bool* flag; - public: - FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; } - ~FlagSetting() { *flag = val; } -}; - - -class CounterSetting { - intx* counter; - public: - CounterSetting(intx* cnt) { counter = cnt; (*counter)++; } - ~CounterSetting() { (*counter)--; } -}; - -class IntFlagSetting { - int val; - int* flag; - public: - IntFlagSetting(int& fl, int newValue) { flag = &fl; val = fl; fl = newValue; } - ~IntFlagSetting() { *flag = val; } -}; - -class UIntFlagSetting { - uint val; - uint* flag; - public: - UIntFlagSetting(uint& fl, uint newValue) { flag = &fl; val = fl; fl = newValue; } - ~UIntFlagSetting() { *flag = val; } -}; - -class UIntXFlagSetting { - uintx val; - uintx* flag; - public: - UIntXFlagSetting(uintx& fl, uintx newValue) { flag = &fl; val = fl; fl = newValue; } - ~UIntXFlagSetting() { *flag = val; } -}; - -class DoubleFlagSetting { - double val; - double* flag; - public: - DoubleFlagSetting(double& fl, double newValue) { flag = &fl; val = fl; fl = newValue; } - ~DoubleFlagSetting() { *flag = val; } -}; - -class SizeTFlagSetting { - size_t val; - size_t* flag; - public: - SizeTFlagSetting(size_t& fl, size_t newValue) { flag = &fl; val = fl; fl = newValue; } - ~SizeTFlagSetting() { *flag = val; } -}; - -// Helper class for temporarily saving the value of a flag during a scope. -template -class FlagGuard { - unsigned char _value[SIZE]; - void* const _addr; - - // Hide operator new, this class should only be allocated on the stack. - // NOTE: Cannot include memory/allocation.hpp here due to circular - // dependencies. - void* operator new(size_t size) throw(); - void* operator new [](size_t size) throw(); - - public: - FlagGuard(void* flag_addr) : _addr(flag_addr) { - memcpy(_value, _addr, SIZE); - } - - ~FlagGuard() { - memcpy(_addr, _value, SIZE); - } -}; - -#define FLAG_GUARD(f) FlagGuard f ## _guard(&f) - -class CommandLineFlags { -public: - static Flag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error boolAtPut(Flag* flag, bool* value, Flag::Flags origin); - static Flag::Error boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin); - static Flag::Error boolAtPut(const char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); } - - static Flag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error intAtPut(Flag* flag, int* value, Flag::Flags origin); - static Flag::Error intAtPut(const char* name, size_t len, int* value, Flag::Flags origin); - static Flag::Error intAtPut(const char* name, int* value, Flag::Flags origin) { return intAtPut(name, strlen(name), value, origin); } - - static Flag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error uintAtPut(Flag* flag, uint* value, Flag::Flags origin); - static Flag::Error uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin); - static Flag::Error uintAtPut(const char* name, uint* value, Flag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); } - - static Flag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error intxAtPut(Flag* flag, intx* value, Flag::Flags origin); - static Flag::Error intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin); - static Flag::Error intxAtPut(const char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); } - - static Flag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error uintxAtPut(Flag* flag, uintx* value, Flag::Flags origin); - static Flag::Error uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin); - static Flag::Error uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); } - - static Flag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error size_tAtPut(Flag* flag, size_t* value, Flag::Flags origin); - static Flag::Error size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin); - static Flag::Error size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); } - - static Flag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error uint64_tAtPut(Flag* flag, uint64_t* value, Flag::Flags origin); - static Flag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin); - static Flag::Error uint64_tAtPut(const char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); } - - static Flag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); } - static Flag::Error doubleAtPut(Flag* flag, double* value, Flag::Flags origin); - static Flag::Error doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin); - static Flag::Error doubleAtPut(const char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); } - - static Flag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false); - static Flag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); } - // Contract: Flag will make private copy of the incoming value. - // Outgoing value is always malloc-ed, and caller MUST call free. - static Flag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin); - static Flag::Error ccstrAtPut(const char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); } - - // Returns false if name is not a command line flag. - static bool wasSetOnCmdline(const char* name, bool* value); - static void printSetFlags(outputStream* out); - - // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges - static void printFlags(outputStream* out, bool withComments, bool printRanges = false); - - static void verify() PRODUCT_RETURN; -}; - // use this for flags that are true by default in the debug version but // false in the optimized version, and vice versa #ifdef ASSERT @@ -536,10 +193,10 @@ public: // it can be done in the same way as product_rw. // // range is a macro that will expand to min and max arguments for range -// checking code if provided - see commandLineFlagRangeList.hpp +// checking code if provided - see jvmFlagRangeList.hpp // // constraint is a macro that will expand to custom function call -// for constraint checking if provided - see commandLineFlagConstraintList.hpp +// for constraint checking if provided - see jvmFlagConstraintList.hpp // // writeable is a macro that controls if and how the value can change during the runtime // diff --git a/src/hotspot/share/runtime/globals_ext.hpp b/src/hotspot/share/runtime/globals_ext.hpp index f3d4c992668..e8d400267f6 100644 --- a/src/hotspot/share/runtime/globals_ext.hpp +++ b/src/hotspot/share/runtime/globals_ext.hpp @@ -25,13 +25,15 @@ #ifndef SHARE_VM_RUNTIME_GLOBALS_EXT_HPP #define SHARE_VM_RUNTIME_GLOBALS_EXT_HPP +#include "runtime/flags/jvmFlag.hpp" + // globals_extension.hpp extension -// Additional CommandLineFlags enum values -#define COMMANDLINEFLAG_EXT +// Additional JVMFlags enum values +#define JVMFLAGS_EXT -// Additional CommandLineFlagsWithType enum values -#define COMMANDLINEFLAGWITHTYPE_EXT +// Additional JVMFlagsWithType enum values +#define JVMFLAGSWITHTYPE_EXT // globals.cpp extension @@ -45,26 +47,26 @@ // Default method implementations -inline bool Flag::is_unlocker_ext() const { +inline bool JVMFlag::is_unlocker_ext() const { return false; } -inline bool Flag::is_unlocked_ext() const { +inline bool JVMFlag::is_unlocked_ext() const { return true; } -inline bool Flag::is_writeable_ext() const { +inline bool JVMFlag::is_writeable_ext() const { return false; } -inline bool Flag::is_external_ext() const { +inline bool JVMFlag::is_external_ext() const { return false; } -inline Flag::MsgType Flag::get_locked_message_ext(char* buf, int buflen) const { +inline JVMFlag::MsgType JVMFlag::get_locked_message_ext(char* buf, int buflen) const { assert(buf != NULL, "Buffer cannot be NULL"); buf[0] = '\0'; - return Flag::NONE; + return JVMFlag::NONE; } #endif // SHARE_VM_RUNTIME_GLOBALS_EXT_HPP diff --git a/src/hotspot/share/runtime/globals_extension.hpp b/src/hotspot/share/runtime/globals_extension.hpp index 38c8701715f..0297b3d08db 100644 --- a/src/hotspot/share/runtime/globals_extension.hpp +++ b/src/hotspot/share/runtime/globals_extension.hpp @@ -27,7 +27,6 @@ #include "runtime/globals.hpp" #include "utilities/macros.hpp" -#include "utilities/macros.hpp" #if INCLUDE_JVMCI #include "jvmci/jvmci_globals.hpp" #endif @@ -164,9 +163,9 @@ typedef enum { IGNORE_RANGE, \ IGNORE_CONSTRAINT, \ IGNORE_WRITEABLE) - COMMANDLINEFLAG_EXT - NUM_CommandLineFlag -} CommandLineFlag; + JVMFLAGS_EXT + NUM_JVMFlags +} JVMFlags; // Construct enum of Flag__ constants. @@ -293,19 +292,19 @@ typedef enum { IGNORE_RANGE, IGNORE_CONSTRAINT, IGNORE_WRITEABLE) - COMMANDLINEFLAGWITHTYPE_EXT - NUM_CommandLineFlagWithType -} CommandLineFlagWithType; + JVMFLAGSWITHTYPE_EXT + NUM_JVMFlagsWithType +} JVMFlagsWithType; -#define FLAG_IS_DEFAULT(name) (CommandLineFlagsEx::is_default(FLAG_MEMBER(name))) -#define FLAG_IS_ERGO(name) (CommandLineFlagsEx::is_ergo(FLAG_MEMBER(name))) -#define FLAG_IS_CMDLINE(name) (CommandLineFlagsEx::is_cmdline(FLAG_MEMBER(name))) +#define FLAG_IS_DEFAULT(name) (JVMFlagEx::is_default(FLAG_MEMBER(name))) +#define FLAG_IS_ERGO(name) (JVMFlagEx::is_ergo(FLAG_MEMBER(name))) +#define FLAG_IS_CMDLINE(name) (JVMFlagEx::is_cmdline(FLAG_MEMBER(name))) #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) -#define FLAG_SET_CMDLINE(type, name, value) (CommandLineFlagsEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \ - CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), Flag::COMMAND_LINE)) -#define FLAG_SET_ERGO(type, name, value) (CommandLineFlagsEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), Flag::ERGONOMIC)) +#define FLAG_SET_CMDLINE(type, name, value) (JVMFlagEx::setOnCmdLine(FLAG_MEMBER_WITH_TYPE(name, type)), \ + JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::COMMAND_LINE)) +#define FLAG_SET_ERGO(type, name, value) (JVMFlagEx::type##AtPut(FLAG_MEMBER_WITH_TYPE(name, type), (type)(value), JVMFlag::ERGONOMIC)) #define FLAG_SET_ERGO_IF_DEFAULT(type, name, value) \ do { \ if (FLAG_IS_DEFAULT(name)) { \ @@ -313,26 +312,26 @@ typedef enum { } \ } while (0) -// Can't put the following in CommandLineFlags because +// Can't put the following in JVMFlags because // of a circular dependency on the enum definition. -class CommandLineFlagsEx : CommandLineFlags { +class JVMFlagEx : JVMFlag { public: - static Flag::Error boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin); - static Flag::Error intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin); - static Flag::Error uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin); - static Flag::Error intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin); - static Flag::Error uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin); - static Flag::Error uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin); - static Flag::Error size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin); - static Flag::Error doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin); + static JVMFlag::Error boolAtPut(JVMFlagsWithType flag, bool value, JVMFlag::Flags origin); + static JVMFlag::Error intAtPut(JVMFlagsWithType flag, int value, JVMFlag::Flags origin); + static JVMFlag::Error uintAtPut(JVMFlagsWithType flag, uint value, JVMFlag::Flags origin); + static JVMFlag::Error intxAtPut(JVMFlagsWithType flag, intx value, JVMFlag::Flags origin); + static JVMFlag::Error uintxAtPut(JVMFlagsWithType flag, uintx value, JVMFlag::Flags origin); + static JVMFlag::Error uint64_tAtPut(JVMFlagsWithType flag, uint64_t value, JVMFlag::Flags origin); + static JVMFlag::Error size_tAtPut(JVMFlagsWithType flag, size_t value, JVMFlag::Flags origin); + static JVMFlag::Error doubleAtPut(JVMFlagsWithType flag, double value, JVMFlag::Flags origin); // Contract: Flag will make private copy of the incoming value - static Flag::Error ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin); + static JVMFlag::Error ccstrAtPut(JVMFlagsWithType flag, ccstr value, JVMFlag::Flags origin); - static bool is_default(CommandLineFlag flag); - static bool is_ergo(CommandLineFlag flag); - static bool is_cmdline(CommandLineFlag flag); + static bool is_default(JVMFlags flag); + static bool is_ergo(JVMFlags flag); + static bool is_cmdline(JVMFlags flag); - static void setOnCmdLine(CommandLineFlagWithType flag); + static void setOnCmdLine(JVMFlagsWithType flag); }; #endif // SHARE_VM_RUNTIME_GLOBALS_EXTENSION_HPP diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index a903eef7c39..7836e558888 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_HANDSHAKE_HPP #include "memory/allocation.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/semaphore.hpp" class ThreadClosure; diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 944ddeb83a9..6c4d000267f 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -30,7 +30,7 @@ #include "interpreter/bytecodes.hpp" #include "memory/universe.hpp" #include "prims/methodHandles.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" #include "runtime/init.hpp" @@ -155,7 +155,7 @@ jint init_globals() { // All the flags that get adjusted by VM_Version_init and os::init_2 // have been set so dump the flags now. if (PrintFlagsFinal || PrintFlagsRanges) { - CommandLineFlags::printFlags(tty, false, PrintFlagsRanges); + JVMFlag::printFlags(tty, false, PrintFlagsRanges); } return JNI_OK; diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index c1c8a3d1bca..fd17e47a48e 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -54,6 +54,7 @@ #include "runtime/biasedLocking.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 7a0cd44c099..e94dcd0286e 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_MUTEXLOCKER_HPP #include "memory/allocation.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/mutex.hpp" // Mutexes used in the VM. diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index b70e3025039..ff9a38a3d45 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -63,12 +63,11 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/commandLineFlagConstraintList.hpp" -#include "runtime/commandLineFlagWriteableList.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlagConstraintList.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" +#include "runtime/flags/jvmFlagWriteableList.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" -#include "runtime/globals.hpp" #include "runtime/handshake.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -3663,17 +3662,17 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { if (ergo_result != JNI_OK) return ergo_result; // Final check of all ranges after ergonomics which may change values. - if (!CommandLineFlagRangeList::check_ranges()) { + if (!JVMFlagRangeList::check_ranges()) { return JNI_EINVAL; } // Final check of all 'AfterErgo' constraints after ergonomics which may change values. - bool constraint_result = CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterErgo); + bool constraint_result = JVMFlagConstraintList::check_constraints(JVMFlagConstraint::AfterErgo); if (!constraint_result) { return JNI_EINVAL; } - CommandLineFlagWriteableList::mark_startup(); + JVMFlagWriteableList::mark_startup(); if (PauseAtStartup) { os::pause(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index fd473a58268..ecbd665b92e 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -83,6 +83,7 @@ #include "prims/jvmtiAgentThread.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" @@ -718,7 +719,7 @@ typedef PaddedEnd PaddedObjectMonitor; nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ - nonstatic_field(nmethod, _state, volatile signed char) \ + nonstatic_field(nmethod, _state, volatile signed char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ @@ -1062,12 +1063,12 @@ typedef PaddedEnd PaddedObjectMonitor; /* -XX flags */ \ /*********************/ \ \ - nonstatic_field(Flag, _type, const char*) \ - nonstatic_field(Flag, _name, const char*) \ - unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) /* NOTE: no type */ \ - nonstatic_field(Flag, _flags, Flag::Flags) \ - static_field(Flag, flags, Flag*) \ - static_field(Flag, numFlags, size_t) \ + nonstatic_field(JVMFlag, _type, const char*) \ + nonstatic_field(JVMFlag, _name, const char*) \ + unchecked_nonstatic_field(JVMFlag, _addr, sizeof(void*)) /* NOTE: no type */ \ + nonstatic_field(JVMFlag, _flags, JVMFlag::Flags) \ + static_field(JVMFlag, flags, JVMFlag*) \ + static_field(JVMFlag, numFlags, size_t) \ \ /*************************/ \ /* JDK / VM version info */ \ @@ -1444,14 +1445,14 @@ typedef PaddedEnd PaddedObjectMonitor; declare_toplevel_type(SharedRuntime) \ \ declare_toplevel_type(CodeBlob) \ - declare_type(RuntimeBlob, CodeBlob) \ - declare_type(BufferBlob, RuntimeBlob) \ + declare_type(RuntimeBlob, CodeBlob) \ + declare_type(BufferBlob, RuntimeBlob) \ declare_type(AdapterBlob, BufferBlob) \ declare_type(MethodHandlesAdapterBlob, BufferBlob) \ declare_type(CompiledMethod, CodeBlob) \ declare_type(nmethod, CompiledMethod) \ - declare_type(RuntimeStub, RuntimeBlob) \ - declare_type(SingletonBlob, RuntimeBlob) \ + declare_type(RuntimeStub, RuntimeBlob) \ + declare_type(SingletonBlob, RuntimeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ @@ -1910,8 +1911,8 @@ typedef PaddedEnd PaddedObjectMonitor; /* -XX flags */ \ /********************/ \ \ - declare_toplevel_type(Flag) \ - declare_toplevel_type(Flag*) \ + declare_toplevel_type(JVMFlag) \ + declare_toplevel_type(JVMFlag*) \ \ /********************/ \ /* JVMTI */ \ @@ -1951,7 +1952,7 @@ typedef PaddedEnd PaddedObjectMonitor; declare_integer_type(ThreadState) \ declare_integer_type(Location::Type) \ declare_integer_type(Location::Where) \ - declare_integer_type(Flag::Flags) \ + declare_integer_type(JVMFlag::Flags) \ COMPILER2_PRESENT(declare_integer_type(OptoReg::Name)) \ \ declare_toplevel_type(CHeapObj) \ diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index ff4705cb8f6..8264727e086 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -31,6 +31,7 @@ #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -275,9 +276,9 @@ static jint set_flag(AttachOperation* op, outputStream* out) { FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), Flag::ATTACH_ON_DEMAND, err_msg); - if (ret != Flag::SUCCESS) { - if (ret == Flag::NON_WRITABLE) { + int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); + if (ret != JVMFlag::SUCCESS) { + if (ret == JVMFlag::NON_WRITABLE) { // if the flag is not manageable try to change it through // the platform dependent implementation return AttachListener::pd_set_flag(op, out); @@ -298,7 +299,7 @@ static jint print_flag(AttachOperation* op, outputStream* out) { out->print_cr("flag name is missing"); return JNI_ERR; } - Flag* f = Flag::find_flag((char*)name, strlen(name)); + JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name)); if (f) { f->print_as_flag(out); out->cr(); diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index ce7de97dffa..0c5388168a8 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -33,7 +33,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" -#include "runtime/globals.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" @@ -231,9 +231,9 @@ PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) : void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) { if (_all.value()) { - CommandLineFlags::printFlags(output(), true); + JVMFlag::printFlags(output(), true); } else { - CommandLineFlags::printSetFlags(output()); + JVMFlag::printSetFlags(output()); } } @@ -264,9 +264,9 @@ void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) { } FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(_flag.value(), val, Flag::MANAGEMENT, err_msg); + int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlag::MANAGEMENT, err_msg); - if (ret != Flag::SUCCESS) { + if (ret != JVMFlag::SUCCESS) { output()->print_cr("%s", err_msg.buffer()); } } diff --git a/src/hotspot/share/services/dtraceAttacher.cpp b/src/hotspot/share/services/dtraceAttacher.cpp index d923bc1282e..2d7e32c2ddc 100644 --- a/src/hotspot/share/services/dtraceAttacher.cpp +++ b/src/hotspot/share/services/dtraceAttacher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "code/codeCache.hpp" #include "memory/resourceArea.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/dtraceAttacher.hpp" @@ -50,8 +51,8 @@ class VM_DeoptimizeTheWorld : public VM_Operation { }; static void set_bool_flag(const char* flag, bool value) { - CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value, - Flag::ATTACH_ON_DEMAND); + JVMFlag::boolAtPut((char*)flag, strlen(flag), &value, + JVMFlag::ATTACH_ON_DEMAND); } // Enable only the "fine grained" flags. Do *not* touch diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index a75ae1a6a43..ec44089c18f 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -36,6 +36,7 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -866,10 +867,10 @@ static jint get_vm_thread_count() { static jint get_num_flags() { // last flag entry is always NULL, so subtract 1 - int nFlags = (int) Flag::numFlags - 1; + int nFlags = (int) JVMFlag::numFlags - 1; int count = 0; for (int i = 0; i < nFlags; i++) { - Flag* flag = &Flag::flags[i]; + JVMFlag* flag = &JVMFlag::flags[i]; // Exclude the locked (diagnostic, experimental) flags if (flag->is_unlocked() || flag->is_unlocker()) { count++; @@ -1419,14 +1420,14 @@ JVM_END // Returns a String array of all VM global flag names JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env)) // last flag entry is always NULL, so subtract 1 - int nFlags = (int) Flag::numFlags - 1; + int nFlags = (int) JVMFlag::numFlags - 1; // allocate a temp array objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), nFlags, CHECK_0); objArrayHandle flags_ah(THREAD, r); int num_entries = 0; for (int i = 0; i < nFlags; i++) { - Flag* flag = &Flag::flags[i]; + JVMFlag* flag = &JVMFlag::flags[i]; // Exclude notproduct and develop flags in product builds. if (flag->is_constant_in_binary()) { continue; @@ -1454,7 +1455,7 @@ JVM_END // Utility function used by jmm_GetVMGlobals. Returns false if flag type // can't be determined, true otherwise. If false is returned, then *global // will be incomplete and invalid. -bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { +bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, JVMFlag *flag, TRAPS) { Handle flag_name; if (name() == NULL) { flag_name = java_lang_String::create_from_str(flag->_name, CHECK_false); @@ -1499,25 +1500,25 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, global->writeable = flag->is_writeable(); global->external = flag->is_external(); switch (flag->get_origin()) { - case Flag::DEFAULT: + case JVMFlag::DEFAULT: global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT; break; - case Flag::COMMAND_LINE: + case JVMFlag::COMMAND_LINE: global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE; break; - case Flag::ENVIRON_VAR: + case JVMFlag::ENVIRON_VAR: global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR; break; - case Flag::CONFIG_FILE: + case JVMFlag::CONFIG_FILE: global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE; break; - case Flag::MANAGEMENT: + case JVMFlag::MANAGEMENT: global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT; break; - case Flag::ERGONOMIC: + case JVMFlag::ERGONOMIC: global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC; break; - case Flag::ATTACH_ON_DEMAND: + case JVMFlag::ATTACH_ON_DEMAND: global->origin = JMM_VMGLOBAL_ORIGIN_ATTACH_ON_DEMAND; break; default: @@ -1531,7 +1532,7 @@ bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, // specified by names. If names == NULL, fill globals array // with all Flags. Return value is number of entries // created in globals. -// If a Flag with a given name in an array element does not +// If a JVMFlag with a given name in an array element does not // exist, globals[i].name will be set to NULL. JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, jobjectArray names, @@ -1566,7 +1567,7 @@ JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, Handle sh(THREAD, s); char* str = java_lang_String::as_utf8_string(s); - Flag* flag = Flag::find_flag(str, strlen(str)); + JVMFlag* flag = JVMFlag::find_flag(str, strlen(str)); if (flag != NULL && add_global_entry(env, sh, &globals[i], flag, THREAD)) { num_entries++; @@ -1579,11 +1580,11 @@ JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env, // return all globals if names == NULL // last flag entry is always NULL, so subtract 1 - int nFlags = (int) Flag::numFlags - 1; + int nFlags = (int) JVMFlag::numFlags - 1; Handle null_h; int num_entries = 0; for (int i = 0; i < nFlags && num_entries < count; i++) { - Flag* flag = &Flag::flags[i]; + JVMFlag* flag = &JVMFlag::flags[i]; // Exclude notproduct and develop flags in product builds. if (flag->is_constant_in_binary()) { continue; @@ -1609,10 +1610,10 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value char* name = java_lang_String::as_utf8_string(fn); FormatBuffer<80> error_msg("%s", ""); - int succeed = WriteableFlags::set_flag(name, new_value, Flag::MANAGEMENT, error_msg); + int succeed = WriteableFlags::set_flag(name, new_value, JVMFlag::MANAGEMENT, error_msg); - if (succeed != Flag::SUCCESS) { - if (succeed == Flag::MISSING_VALUE) { + if (succeed != JVMFlag::SUCCESS) { + if (succeed == JVMFlag::MISSING_VALUE) { // missing value causes NPE to be thrown THROW(vmSymbols::java_lang_NullPointerException()); } else { @@ -1621,7 +1622,7 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value error_msg.buffer()); } } - assert(succeed == Flag::SUCCESS, "Setting flag should succeed"); + assert(succeed == JVMFlag::SUCCESS, "Setting flag should succeed"); JVM_END class ThreadTimesClosure: public ThreadClosure { diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp index 54b59635c2e..fee4e68b51f 100644 --- a/src/hotspot/share/services/writeableFlags.cpp +++ b/src/hotspot/share/services/writeableFlags.cpp @@ -26,7 +26,8 @@ #include "classfile/javaClasses.hpp" #include "memory/allocation.inline.hpp" #include "runtime/arguments.hpp" -#include "runtime/commandLineFlagRangeList.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/flags/jvmFlagRangeList.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" #include "services/writeableFlags.hpp" @@ -38,7 +39,7 @@ static void buffer_concat(char* buffer, const char* src) { } static void print_flag_error_message_bounds(const char* name, char* buffer) { - CommandLineFlagRange* range = CommandLineFlagRangeList::find(name); + JVMFlagRange* range = JVMFlagRangeList::find(name); if (range != NULL) { buffer_concat(buffer, "must have value in range "); @@ -58,34 +59,34 @@ static void print_flag_error_message_bounds(const char* name, char* buffer) { } } -static void print_flag_error_message_if_needed(Flag::Error error, const char* name, FormatBuffer<80>& err_msg) { - if (error == Flag::SUCCESS) { +static void print_flag_error_message_if_needed(JVMFlag::Error error, const char* name, FormatBuffer<80>& err_msg) { + if (error == JVMFlag::SUCCESS) { return; } char buffer[TEMP_BUF_SIZE] = {'\0'}; - if ((error != Flag::MISSING_NAME) && (name != NULL)) { + if ((error != JVMFlag::MISSING_NAME) && (name != NULL)) { buffer_concat(buffer, name); buffer_concat(buffer, " error: "); } else { buffer_concat(buffer, "Error: "); } switch (error) { - case Flag::MISSING_NAME: + case JVMFlag::MISSING_NAME: buffer_concat(buffer, "flag name is missing."); break; - case Flag::MISSING_VALUE: + case JVMFlag::MISSING_VALUE: buffer_concat(buffer, "parsing the textual form of the value."); break; - case Flag::NON_WRITABLE: + case JVMFlag::NON_WRITABLE: buffer_concat(buffer, "flag is not writeable."); break; - case Flag::OUT_OF_BOUNDS: + case JVMFlag::OUT_OF_BOUNDS: print_flag_error_message_bounds(name, buffer); break; - case Flag::VIOLATES_CONSTRAINT: + case JVMFlag::VIOLATES_CONSTRAINT: buffer_concat(buffer, "value violates its flag's constraint."); break; - case Flag::INVALID_FLAG: + case JVMFlag::INVALID_FLAG: buffer_concat(buffer, "there is no flag with the given name."); break; - case Flag::ERR_OTHER: + case JVMFlag::ERR_OTHER: buffer_concat(buffer, "other, unspecified error related to setting the flag."); break; - case Flag::SUCCESS: + case JVMFlag::SUCCESS: break; default: break; @@ -95,127 +96,127 @@ static void print_flag_error_message_if_needed(Flag::Error error, const char* na } // set a boolean global flag -Flag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { if ((strcasecmp(arg, "true") == 0) || (*arg == '1' && *(arg + 1) == 0)) { return set_bool_flag(name, true, origin, err_msg); } else if ((strcasecmp(arg, "false") == 0) || (*arg == '0' && *(arg + 1) == 0)) { return set_bool_flag(name, false, origin, err_msg); } err_msg.print("flag value must be a boolean (1/0 or true/false)"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::boolAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::boolAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a int global flag -Flag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { int value; if (sscanf(arg, "%d", &value)) { return set_int_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::intAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::intAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uint global flag -Flag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { uint value; if (sscanf(arg, "%u", &value)) { return set_uint_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::uintAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::uintAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a intx global flag -Flag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { intx value; if (sscanf(arg, INTX_FORMAT, &value)) { return set_intx_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::intxAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::intxAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uintx global flag -Flag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { uintx value; if (sscanf(arg, UINTX_FORMAT, &value)) { return set_uintx_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::uintxAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::uintxAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a uint64_t global flag -Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { uint64_t value; if (sscanf(arg, UINT64_FORMAT, &value)) { return set_uint64_t_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned 64-bit integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::uint64_tAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::uint64_tAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a size_t global flag -Flag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { size_t value; if (sscanf(arg, SIZE_FORMAT, &value)) { return set_size_t_flag(name, value, origin, err_msg); } err_msg.print("flag value must be an unsigned integer"); - return Flag::WRONG_FORMAT; + return JVMFlag::WRONG_FORMAT; } -Flag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::size_tAtPut(name, &value, origin); +JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::size_tAtPut(name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } // set a string global flag using value from AttachOperation -Flag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { - Flag::Error err = CommandLineFlags::ccstrAtPut((char*)name, &value, origin); +JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { + JVMFlag::Error err = JVMFlag::ccstrAtPut((char*)name, &value, origin); print_flag_error_message_if_needed(err, name, err_msg); return err; } @@ -225,7 +226,7 @@ Flag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -Flag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg); } @@ -234,42 +235,42 @@ Flag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_val * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -Flag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg); } // a writeable flag setter accepting either 'jvalue' or 'char *' values -Flag::Error WriteableFlags::set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*,const void*,Flag::Flags,FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlag::Flags,FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { if (name == NULL) { err_msg.print("flag name is missing"); - return Flag::MISSING_NAME; + return JVMFlag::MISSING_NAME; } if (value == NULL) { err_msg.print("flag value is missing"); - return Flag::MISSING_VALUE; + return JVMFlag::MISSING_VALUE; } - Flag* f = Flag::find_flag((char*)name, strlen(name)); + JVMFlag* f = JVMFlag::find_flag((char*)name, strlen(name)); if (f) { // only writeable flags are allowed to be set if (f->is_writeable()) { return setter(f, value, origin, err_msg); } else { err_msg.print("only 'writeable' flags can be set"); - return Flag::NON_WRITABLE; + return JVMFlag::NON_WRITABLE; } } err_msg.print("flag %s does not exist", name); - return Flag::INVALID_FLAG; + return JVMFlag::INVALID_FLAG; } // a writeable flag setter accepting 'char *' values -Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { char* flag_value = *(char**)value; if (flag_value == NULL) { err_msg.print("flag value is missing"); - return Flag::MISSING_VALUE; + return JVMFlag::MISSING_VALUE; } if (f->is_bool()) { return set_bool_flag(f->_name, flag_value, origin, err_msg); @@ -290,11 +291,11 @@ Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag: } else { ShouldNotReachHere(); } - return Flag::ERR_OTHER; + return JVMFlag::ERR_OTHER; } // a writeable flag setter accepting 'jvalue' values -Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, +JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { jvalue new_value = *(jvalue*)value; if (f->is_bool()) { @@ -322,16 +323,16 @@ Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Fla oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { err_msg.print("flag value is missing"); - return Flag::MISSING_VALUE; + return JVMFlag::MISSING_VALUE; } ccstr svalue = java_lang_String::as_utf8_string(str); - Flag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg); - if (ret != Flag::SUCCESS) { + JVMFlag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg); + if (ret != JVMFlag::SUCCESS) { FREE_C_HEAP_ARRAY(char, svalue); } return ret; } else { ShouldNotReachHere(); } - return Flag::ERR_OTHER; + return JVMFlag::ERR_OTHER; } diff --git a/src/hotspot/share/services/writeableFlags.hpp b/src/hotspot/share/services/writeableFlags.hpp index caa6e0a4757..31065982c4c 100644 --- a/src/hotspot/share/services/writeableFlags.hpp +++ b/src/hotspot/share/services/writeableFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,48 +25,49 @@ #ifndef SHARE_VM_SERVICES_WRITEABLEFLAG_HPP #define SHARE_VM_SERVICES_WRITEABLEFLAG_HPP +#include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" #include "utilities/formatBuffer.hpp" class WriteableFlags : AllStatic { private: // a writeable flag setter accepting either 'jvalue' or 'char *' values - static Flag::Error set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*, const void*, Flag::Flags, FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*, const void*, JVMFlag::Flags, FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'char *' values - static Flag::Error set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'jvalue' values - static Flag::Error set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static Flag::Error set_bool_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_bool_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a int global flag - static Flag::Error set_int_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_int_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint global flag - static Flag::Error set_uint_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a intx global flag - static Flag::Error set_intx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_intx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static Flag::Error set_uintx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uintx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static Flag::Error set_uint64_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint64_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static Flag::Error set_size_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_size_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static Flag::Error set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a int global flag - static Flag::Error set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint global flag - static Flag::Error set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a intx global flag - static Flag::Error set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static Flag::Error set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static Flag::Error set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static Flag::Error set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); // set a string global flag - static Flag::Error set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); public: /* sets a writeable flag to the provided value @@ -74,14 +75,14 @@ public: * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static Flag::Error set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); /* sets a writeable flag to the provided value * * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static Flag::Error set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); }; #endif /* SHARE_VM_SERVICES_WRITEABLEFLAG_HPP */ diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 71bbe5709e2..1fa5d655058 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -40,6 +40,7 @@ #include "prims/privilegedStack.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index a6b9fdef58c..91772d15eba 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1259,4 +1259,11 @@ static inline void* dereference_vptr(const void* addr) { return *(void**)addr; } +//---------------------------------------------------------------------------------------------------- +// String type aliases used by command line flag declarations and +// processing utilities. + +typedef const char* ccstr; +typedef const char* ccstrlist; // represents string arguments which accumulate + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_HPP diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 465937dc822..bbfe6e65e99 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -137,7 +137,7 @@ public class VM { private Boolean compressedOopsEnabled; private Boolean compressedKlassPointersEnabled; - // command line flags supplied to VM - see struct Flag in globals.hpp + // command line flags supplied to VM - see struct JVMFlag in jvmFlag.hpp public static final class Flag { private String type; private String name; @@ -916,7 +916,7 @@ public class VM { private void readCommandLineFlags() { // get command line flags TypeDataBase db = getTypeDataBase(); - Type flagType = db.lookupType("Flag"); + Type flagType = db.lookupType("JVMFlag"); int numFlags = (int) flagType.getCIntegerField("numFlags").getValue(); // NOTE: last flag contains null values. commandLineFlags = new Flag[numFlags - 1]; diff --git a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp index 5fd493fa802..ce50b73a690 100644 --- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp +++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/collectorPolicy.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/test/hotspot/gtest/runtime/test_globals.cpp b/test/hotspot/gtest/runtime/test_globals.cpp index 3a84f2ce714..d2d3ed262af 100644 --- a/test/hotspot/gtest/runtime/test_globals.cpp +++ b/test/hotspot/gtest/runtime/test_globals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,18 @@ #include "precompiled.hpp" #include "runtime/globals.hpp" +#include "runtime/flags/flagSetting.hpp" #include "unittest.hpp" -#define TEST_FLAG(f, type, value) \ - do { \ - ASSERT_TRUE(Flag::find_flag(#f)->is_ ## type()); \ - type original_value = f; \ - { \ - FLAG_GUARD(f); \ - f = value; \ - } \ - ASSERT_EQ(original_value, f); \ +#define TEST_FLAG(f, type, value) \ + do { \ + ASSERT_TRUE(JVMFlag::find_flag(#f)->is_ ## type()); \ + type original_value = f; \ + { \ + FLAG_GUARD(f); \ + f = value; \ + } \ + ASSERT_EQ(original_value, f); \ } while (0) TEST_VM(FlagGuard, bool_flag) { From 3105e04e1b483c09ea9e5ec442a818942e8198d1 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 26 Apr 2018 18:55:44 +0000 Subject: [PATCH 058/102] Added tag jdk-11+11 for changeset e1e60f75cd39 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8ee114f2ca4..fa59fd4ea7c 100644 --- a/.hgtags +++ b/.hgtags @@ -482,3 +482,4 @@ f7363de371c9a1f668bd0a01b7df3d1ddb9cc58b jdk-11+7 0c3e252cea44f06aef570ef464950ab97c669970 jdk-11+9 6fa770f9f8ab296e1ce255ec17ccf6d4e1051886 jdk-10+46 69d7398038c54774d9395b6810e0cca335edc02c jdk-11+10 +e1e60f75cd39312a7f59d2a4f91d624e5aecc95e jdk-11+11 From fafd844bc69d8c25e5f994d012d76e6e6ae2cad3 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 26 Apr 2018 12:39:15 -0700 Subject: [PATCH 059/102] 8181157: CLDR Timezone name fallback implementation Reviewed-by: sherman, scolebourne --- .../build/tools/cldrconverter/Bundle.java | 40 +-- .../tools/cldrconverter/CLDRConverter.java | 46 ++- .../tools/cldrconverter/LDMLParseHandler.java | 50 +++- .../cldrconverter/MetaZonesParseHandler.java | 13 +- .../ResourceBundleGenerator.java | 31 +- .../classes/java/text/SimpleDateFormat.java | 9 +- .../share/classes/java/util/Locale.java | 6 +- .../util/cldr/CLDRLocaleProviderAdapter.java | 27 +- .../cldr/CLDRTimeZoneNameProviderImpl.java | 272 ++++++++++++++++++ .../provider/JRELocaleProviderAdapter.java | 4 +- .../locale/provider/LocaleDataMetaInfo.java | 9 +- .../util/locale/provider/LocaleResources.java | 42 ++- .../provider/TimeZoneNameProviderImpl.java | 36 +-- .../locale/provider/TimeZoneNameUtility.java | 12 +- .../sun/util/resources/LocaleData.java | 7 +- .../util/resources/TimeZoneNamesBundle.java | 19 +- test/jdk/java/util/TimeZone/Bug8149452.java | 21 +- .../util/TimeZone/CLDRDisplayNamesTest.java | 16 +- test/jdk/java/util/TimeZone/TimeZoneTest.java | 5 +- test/jdk/sun/text/resources/LocaleData.cldr | 2 +- .../sun/text/resources/LocaleDataTest.java | 4 +- .../resources/cldr/TimeZoneNamesTest.java | 123 ++++++++ 22 files changed, 639 insertions(+), 155 deletions(-) create mode 100644 src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java create mode 100644 test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index ba4ab1b8924..f608bc97882 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -318,16 +318,17 @@ class Bundle { } for (Iterator it = myMap.keySet().iterator(); it.hasNext();) { String key = it.next(); - if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX) + if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX) || key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) { @SuppressWarnings("unchecked") Map nameMap = (Map) myMap.get(key); + // Convert key/value pairs to an array. String[] names = new String[ZONE_NAME_KEYS.length]; int ix = 0; for (String nameKey : ZONE_NAME_KEYS) { String name = nameMap.get(nameKey); - if (name == null) { + if (name == null && parentsMap != null) { @SuppressWarnings("unchecked") Map parentNames = (Map) parentsMap.get(key); if (parentNames != null) { @@ -357,29 +358,6 @@ class Bundle { } } } - // If there are still any nulls, try filling in them from en data. - if (hasNulls(names) && !id.equals("en")) { - @SuppressWarnings("unchecked") - String[] enNames = (String[]) Bundle.getBundle("en").getTargetMap().get(key); - if (enNames == null) { - if (metaKey != null) { - @SuppressWarnings("unchecked") - String[] metaNames = (String[]) Bundle.getBundle("en").getTargetMap().get(metaKey); - enNames = metaNames; - } - } - if (enNames != null) { - for (int i = 0; i < names.length; i++) { - if (names[i] == null) { - names[i] = enNames[i]; - } - } - } - // If there are still nulls, give up names. - if (hasNulls(names)) { - names = null; - } - } } // replace the Map with the array if (names != null) { @@ -662,12 +640,12 @@ class Bundle { if (CLDRConverter.handlerMetaZones.get(tz).equals(meta)) { tzid = tz; break; - } } } + } } else { tzid = key.substring(CLDRConverter.TIMEZONE_ID_PREFIX.length()); - } + } if (tzid != null) { for (Object[] jreZone : jreTimeZoneNames) { @@ -676,13 +654,13 @@ class Bundle { if (map.get(ZONE_NAME_KEYS[i]) == null) { String[] jreNames = (String[])jreZone[1]; map.put(ZONE_NAME_KEYS[i], jreNames[i]); + } + } + break; } } - break; } } - } - } private void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { switch (cldrLetter) { diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 1ec839b818b..40ba06a6349 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -31,6 +31,7 @@ import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.*; +import java.text.MessageFormat; import java.time.*; import java.util.*; import java.util.ResourceBundle.Control; @@ -82,9 +83,11 @@ public class CLDRConverter { static final String CALENDAR_FIRSTDAY_PREFIX = "firstDay."; static final String CALENDAR_MINDAYS_PREFIX = "minDays."; static final String TIMEZONE_ID_PREFIX = "timezone.id."; + static final String EXEMPLAR_CITY_PREFIX = "timezone.excity."; static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String METAZONE_ID_PREFIX = "metazone.id."; static final String PARENT_LOCALE_PREFIX = "parentLocale."; + static final String[] EMPTY_ZONE = {"", "", "", "", "", ""}; private static SupplementDataParseHandler handlerSuppl; private static SupplementalMetadataParseHandler handlerSupplMeta; @@ -662,23 +665,18 @@ public class CLDRConverter { Arrays.deepEquals(data, (String[])map.get(METAZONE_ID_PREFIX + me.getValue()))) .findAny(); - if (cldrMeta.isPresent()) { - names.put(tzid, cldrMeta.get().getValue()); - } else { + cldrMeta.ifPresentOrElse(meta -> names.put(tzid, meta.getValue()), () -> { // check the JRE meta key, add if there is not. Optional> jreMeta = jreMetaMap.entrySet().stream() .filter(jm -> Arrays.deepEquals(data, jm.getKey())) .findAny(); - if (jreMeta.isPresent()) { - names.put(tzid, jreMeta.get().getValue()); - } else { - String metaName = "JRE_" + tzid.replaceAll("[/-]", "_"); - names.put(METAZONE_ID_PREFIX + metaName, data); - names.put(tzid, metaName); - jreMetaMap.put(data, metaName); - } - } + jreMeta.ifPresentOrElse(meta -> names.put(tzid, meta.getValue()), () -> { + String metaName = "JRE_" + tzid.replaceAll("[/-]", "_"); + names.put(METAZONE_ID_PREFIX + metaName, data); + names.put(tzid, metaName); + }); + }); } }); } @@ -705,6 +703,26 @@ public class CLDRConverter { } }); + // exemplar cities. + Map exCities = map.entrySet().stream() + .filter(e -> e.getKey().startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX)) + .collect(Collectors + .toMap(Map.Entry::getKey, Map.Entry::getValue)); + names.putAll(exCities); + + if (!id.equals("en") && + !names.isEmpty()) { + // CLDR does not have UTC entry, so add it here. + names.put("UTC", EMPTY_ZONE); + + // no metazone zones + Arrays.asList(handlerMetaZones.get(MetaZonesParseHandler.NO_METAZONE_KEY) + .split("\\s")).stream() + .forEach(tz -> { + names.put(tz, EMPTY_ZONE); + }); + } + return names; } @@ -769,6 +787,10 @@ public class CLDRConverter { "field.hour", "timezone.hourFormat", "timezone.gmtFormat", + "timezone.gmtZeroFormat", + "timezone.regionFormat", + "timezone.regionFormat.daylight", + "timezone.regionFormat.standard", "field.minute", "field.second", "field.zone", diff --git a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java index 34cf8a2d4d3..f45b5a7df60 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,19 +103,30 @@ class LDMLParseHandler extends AbstractLDMLHandler { case "key": // for LocaleNames // copy string - pushStringEntry(qName, attributes, - CLDRConverter.LOCALE_KEY_PREFIX + - convertOldKeyName(attributes.getValue("type"))); + { + String key = convertOldKeyName(attributes.getValue("type")); + if (key.length() == 2) { + pushStringEntry(qName, attributes, + CLDRConverter.LOCALE_KEY_PREFIX + key); + } else { + pushIgnoredContainer(qName); + } + } break; case "type": // for LocaleNames/CalendarNames // copy string - pushStringEntry(qName, attributes, - CLDRConverter.LOCALE_TYPE_PREFIX + - convertOldKeyName(attributes.getValue("key")) + "." + - attributes.getValue("type")); - + { + String key = convertOldKeyName(attributes.getValue("key")); + if (key.length() == 2) { + pushStringEntry(qName, attributes, + CLDRConverter.LOCALE_TYPE_PREFIX + key + "." + + attributes.getValue("type")); + } else { + pushIgnoredContainer(qName); + } + } break; // @@ -445,6 +456,16 @@ class LDMLParseHandler extends AbstractLDMLHandler { case "gmtFormat": pushStringEntry(qName, attributes, "timezone.gmtFormat"); break; + case "gmtZeroFormat": + pushStringEntry(qName, attributes, "timezone.gmtZeroFormat"); + break; + case "regionFormat": + { + String type = attributes.getValue("type"); + pushStringEntry(qName, attributes, "timezone.regionFormat" + + (type == null ? "" : "." + type)); + } + break; case "zone": { String tzid = attributes.getValue("type"); // Olson tz id @@ -474,8 +495,8 @@ class LDMLParseHandler extends AbstractLDMLHandler { case "daylight": // daylight saving (summer) time name pushStringEntry(qName, attributes, CLDRConverter.ZONE_NAME_PREFIX + qName + "." + zoneNameStyle); break; - case "exemplarCity": // not used in JDK - pushIgnoredContainer(qName); + case "exemplarCity": + pushStringEntry(qName, attributes, CLDRConverter.EXEMPLAR_CITY_PREFIX); break; // @@ -877,11 +898,16 @@ class LDMLParseHandler extends AbstractLDMLHandler { case "generic": case "standard": case "daylight": + case "exemplarCity": if (zonePrefix != null && (currentContainer instanceof Entry)) { @SuppressWarnings("unchecked") Map valmap = (Map) get(zonePrefix + getContainerKey()); Entry entry = (Entry) currentContainer; - valmap.put(entry.getKey(), (String) entry.getValue()); + if (qName.equals("exemplarCity")) { + put(CLDRConverter.EXEMPLAR_CITY_PREFIX + getContainerKey(), (String) entry.getValue()); + } else { + valmap.put(entry.getKey(), (String) entry.getValue()); + } } break; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java index e20296587a7..efc1b054952 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java @@ -35,6 +35,8 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; class MetaZonesParseHandler extends AbstractLDMLHandler { + final static String NO_METAZONE_KEY = "no.metazone.defined"; + private String tzid, metazone; // for java.time.format.ZoneNames.java @@ -101,10 +103,17 @@ class MetaZonesParseHandler extends AbstractLDMLHandler { assert qName.equals(currentContainer.getqName()) : "current=" + currentContainer.getqName() + ", param=" + qName; switch (qName) { case "timezone": - if (tzid == null || metazone == null) { + if (tzid == null) { throw new InternalError(); + } else if (metazone == null) { + String no_meta = get(NO_METAZONE_KEY); + put(NO_METAZONE_KEY, no_meta == null ? tzid : no_meta + " " + tzid); + CLDRConverter.info("No metazone defined for %s%n", tzid); + } else { + put(tzid, metazone); } - put(tzid, metazone); + tzid = null; + metazone = null; break; } currentContainer = currentContainer.getParent(); diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 7a882e650f3..9df469fdc5d 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,11 +211,13 @@ class ResourceBundleGenerator implements BundleGenerator { if (value == null) { CLDRConverter.warning("null value for " + key); } else if (value instanceof String) { - if (type == BundleType.TIMEZONE || - ((String)value).startsWith(META_VALUE_PREFIX)) { - out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert((String) value, useJava)); + String valStr = (String)value; + if (type == BundleType.TIMEZONE && + !key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + valStr.startsWith(META_VALUE_PREFIX)) { + out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert(valStr, useJava)); } else { - out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.saveConvert((String) value, useJava)); + out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.saveConvert(valStr, useJava)); } } else if (value instanceof String[]) { String[] values = (String[]) value; @@ -308,15 +310,20 @@ class ResourceBundleGenerator implements BundleGenerator { // end of static initializer block. - // Short TZ names for delayed initialization + // Canonical TZ names for delayed initialization if (CLDRConverter.isBaseModule) { - out.printf(" private static class TZShortIDMapHolder {\n"); - out.printf(" static final Map tzShortIDMap = new HashMap<>();\n"); + out.printf(" private static class TZCanonicalIDMapHolder {\n"); + out.printf(" static final Map tzCanonicalIDMap = new HashMap<>(600);\n"); out.printf(" static {\n"); CLDRConverter.handlerTimeZone.getData().entrySet().stream() .forEach(e -> { - out.printf(" tzShortIDMap.put(\"%s\", \"%s\");\n", e.getKey(), - ((String)e.getValue())); + String[] ids = ((String)e.getValue()).split("\\s"); + out.printf(" tzCanonicalIDMap.put(\"%s\", \"%s\");\n", e.getKey(), + ids[0]); + for (int i = 1; i < ids.length; i++) { + out.printf(" tzCanonicalIDMap.put(\"%s\", \"%s\");\n", ids[i], + ids[0]); + } }); out.printf(" }\n }\n\n"); } @@ -333,8 +340,8 @@ class ResourceBundleGenerator implements BundleGenerator { if (CLDRConverter.isBaseModule) { out.printf(" @Override\n" + - " public Map tzShortIDs() {\n" + - " return TZShortIDMapHolder.tzShortIDMap;\n" + + " public Map tzCanonicalIDs() {\n" + + " return TZCanonicalIDMapHolder.tzCanonicalIDMap;\n" + " }\n\n"); out.printf(" public Map parentLocales() {\n" + " return parentLocalesMap;\n" + diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index 0f36386cbbf..4c41a8244af 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ import java.util.concurrent.ConcurrentMap; import sun.util.calendar.CalendarUtils; import sun.util.calendar.ZoneInfoFile; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.TimeZoneNameUtility; /** * SimpleDateFormat is a concrete class for formatting and @@ -1691,6 +1692,12 @@ public class SimpleDateFormat extends DateFormat { // Checking long and short zones [1 & 2], // and long and short daylight [3 & 4]. String zoneName = zoneNames[i]; + if (zoneName.isEmpty()) { + // fill in by retrieving single name + zoneName = TimeZoneNameUtility.retrieveDisplayName( + zoneNames[0], i >= 3, i % 2, locale); + zoneNames[i] = zoneName; + } if (text.regionMatches(true, start, zoneName, 0, zoneName.length())) { return i; diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index b60c6585b09..f58b67b8ef8 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -2189,9 +2189,9 @@ public final class Locale implements Cloneable, Serializable { } break; case "tz": - displayType = TimeZoneNameUtility.retrieveGenericDisplayName( - TimeZoneNameUtility.convertLDMLShortID(type).orElse(type), - TimeZone.LONG, inLocale); + displayType = TimeZoneNameUtility.convertLDMLShortID(type) + .map(id -> TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.LONG, inLocale)) + .orElse(type); break; } ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"), diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 7bd7454bde1..92cf6c0d183 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.CalendarDataProvider; +import java.util.spi.TimeZoneNameProvider; import sun.util.locale.provider.JRELocaleProviderAdapter; import sun.util.locale.provider.LocaleDataMetaInfo; import sun.util.locale.provider.LocaleProviderAdapter; @@ -130,6 +131,24 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { return null; } + @Override + public TimeZoneNameProvider getTimeZoneNameProvider() { + if (timeZoneNameProvider == null) { + TimeZoneNameProvider provider = AccessController.doPrivileged( + (PrivilegedAction) () -> + new CLDRTimeZoneNameProviderImpl( + getAdapterType(), + getLanguageTagSet("TimeZoneNames"))); + + synchronized (this) { + if (timeZoneNameProvider == null) { + timeZoneNameProvider = provider; + } + } + } + return timeZoneNameProvider; + } + @Override public Locale[] getAvailableLocales() { Set all = createLanguageTagSet("AvailableLocales"); @@ -246,9 +265,9 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { } /** - * Returns the time zone ID from an LDML's short ID + * Returns the canonical ID for the given ID */ - public Optional getTimeZoneID(String shortID) { - return Optional.ofNullable(baseMetaInfo.tzShortIDs().get(shortID)); + public Optional canonicalTZID(String id) { + return Optional.ofNullable(baseMetaInfo.tzCanonicalIDs().get(id)); } } diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java new file mode 100644 index 00000000000..160f413b9c6 --- /dev/null +++ b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.cldr; + +import static sun.util.locale.provider.LocaleProviderAdapter.Type; + +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Locale; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.TimeZone; +import java.util.stream.Collectors; +import sun.util.calendar.ZoneInfoFile; +import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.LocaleResources; +import sun.util.locale.provider.TimeZoneNameProviderImpl; +import sun.util.locale.provider.TimeZoneNameUtility; + +/** + * Concrete implementation of the + * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider} class + * for the CLDR LocaleProviderAdapter. + * + * @author Naoto Sato + */ +public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl { + + private static final String NO_INHERITANCE_MARKER = "\u2205\u2205\u2205"; + private static class AVAILABLE_IDS { + static final String[] INSTANCE = + Arrays.stream(ZoneInfoFile.getZoneIds()) + .sorted() + .toArray(String[]::new); + } + + // display name array indexes + private static final int INDEX_TZID = 0; + private static final int INDEX_STD_LONG = 1; + private static final int INDEX_STD_SHORT = 2; + private static final int INDEX_DST_LONG = 3; + private static final int INDEX_DST_SHORT = 4; + private static final int INDEX_GEN_LONG = 5; + private static final int INDEX_GEN_SHORT = 6; + + public CLDRTimeZoneNameProviderImpl(Type type, Set langtags) { + super(type, langtags); + } + + @Override + protected String[] getDisplayNameArray(String id, Locale locale) { + String tzid = TimeZoneNameUtility.canonicalTZID(id).orElse(id); + String[] namesSuper = super.getDisplayNameArray(tzid, locale); + + if (Objects.nonNull(namesSuper)) { + // CLDR's resource bundle has an translated entry for this id. + // Fix up names if needed, either missing or no-inheritance + namesSuper[INDEX_TZID] = id; + + // Check if standard long name exists. If not, try to retrieve the name + // from language only locale resources. E.g., "Europe/London" + // for en-GB only contains DST names + if (!exists(namesSuper, INDEX_STD_LONG) && !locale.getCountry().isEmpty()) { + String[] names = + getDisplayNameArray(id, Locale.forLanguageTag(locale.getLanguage())); + if (exists(names, INDEX_STD_LONG)) { + namesSuper[INDEX_STD_LONG] = names[INDEX_STD_LONG]; + } + } + + for(int i = INDEX_STD_LONG; i < namesSuper.length; i++) { // index 0 is the 'id' itself + switch (namesSuper[i]) { + case "": + // Fill in empty elements + deriveFallbackName(namesSuper, i, locale, + namesSuper[INDEX_DST_LONG].isEmpty()); + break; + case NO_INHERITANCE_MARKER: + // CLDR's "no inheritance marker" + namesSuper[i] = toGMTFormat(id, i == INDEX_DST_LONG || i == INDEX_DST_SHORT, + i % 2 != 0, locale); + break; + default: + break; + } + } + return namesSuper; + } else { + // Derive the names for this id. Validate the id first. + if (Arrays.binarySearch(AVAILABLE_IDS.INSTANCE, id) >= 0) { + String[] names = new String[INDEX_GEN_SHORT + 1]; + names[INDEX_TZID] = id; + deriveFallbackNames(names, locale); + return names; + } + } + + return null; + } + + @Override + protected String[][] getZoneStrings(Locale locale) { + // Use English for the ROOT locale + locale = locale.equals(Locale.ROOT) ? Locale.ENGLISH : locale; + String[][] ret = super.getZoneStrings(locale); + + // Fill in for the empty names. + // English names are prefilled for performance. + if (locale.getLanguage() != "en") { + for (int zoneIndex = 0; zoneIndex < ret.length; zoneIndex++) { + deriveFallbackNames(ret[zoneIndex], locale); + } + } + return ret; + } + + // Derive fallback time zone name according to LDML's logic + private void deriveFallbackNames(String[] names, Locale locale) { + for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { + deriveFallbackName(names, i, locale, false); + } + } + + private void deriveFallbackName(String[] names, int index, Locale locale, boolean noDST) { + if (exists(names, index)) { + return; + } + + // Check if COMPAT can substitute the name + if (LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) { + String[] compatNames = (String[])LocaleProviderAdapter.forJRE() + .getLocaleResources(locale) + .getTimeZoneNames(names[INDEX_TZID]); + if (compatNames != null) { + for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { + // Assumes COMPAT has no empty slots + if (i == index || !exists(names, i)) { + names[i] = compatNames[i]; + } + } + return; + } + } + + // Type Fallback + if (noDST && typeFallback(names, index)) { + return; + } + + // Region Fallback + if (regionFormatFallback(names, index, locale)) { + return; + } + + // last resort + String id = names[INDEX_TZID].toUpperCase(Locale.ROOT); + if (!id.startsWith("ETC/GMT") && + !id.startsWith("GMT") && + !id.startsWith("UT")) { + names[index] = toGMTFormat(names[INDEX_TZID], + index == INDEX_DST_LONG || index == INDEX_DST_SHORT, + index % 2 != 0, + locale); + } + } + + private boolean exists(String[] names, int index) { + return Objects.nonNull(names) + && Objects.nonNull(names[index]) + && !names[index].isEmpty(); + } + + private boolean typeFallback(String[] names, int index) { + // check generic + int genIndex = INDEX_GEN_SHORT - index % 2; + if (!exists(names, index) && exists(names, genIndex)) { + names[index] = names[genIndex]; + } else { + // check standard + int stdIndex = INDEX_STD_SHORT - index % 2; + if (!exists(names, index) && exists(names, stdIndex)) { + names[index] = names[stdIndex]; + } + } + + return exists(names, index); + } + + private boolean regionFormatFallback(String[] names, int index, Locale l) { + String id = names[INDEX_TZID]; + LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l); + ResourceBundle fd = lr.getJavaTimeFormatData(); + + String rgn = (String) lr.getTimeZoneNames("timezone.excity." + id); + if (rgn == null && !id.startsWith("Etc") && !id.startsWith("SystemV")) { + int slash = id.lastIndexOf('/'); + if (slash > 0) { + rgn = id.substring(slash + 1).replaceAll("_", " "); + } + } + + if (rgn != null) { + String fmt = ""; + switch (index) { + case INDEX_STD_LONG: + fmt = fd.getString("timezone.regionFormat.standard"); + break; + case INDEX_DST_LONG: + fmt = fd.getString("timezone.regionFormat.daylight"); + break; + case INDEX_GEN_LONG: + fmt = fd.getString("timezone.regionFormat"); + break; + } + if (!fmt.isEmpty()) { + names[index] = MessageFormat.format(fmt, rgn); + } + } + + return exists(names, index); + } + + private String toGMTFormat(String id, boolean daylight, boolean isShort, Locale l) { + TimeZone tz = ZoneInfoFile.getZoneInfo(id); + int offset = (tz.getRawOffset() + (daylight ? tz.getDSTSavings() : 0)) / 60000; + LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l); + ResourceBundle fd = lr.getJavaTimeFormatData(); + + if (offset == 0) { + return fd.getString("timezone.gmtZeroFormat"); + } else { + String gmtFormat = fd.getString("timezone.gmtFormat"); + String hourFormat = fd.getString("timezone.hourFormat"); + + if (offset > 0) { + hourFormat = hourFormat.substring(0, hourFormat.indexOf(";")); + } else { + hourFormat = hourFormat.substring(hourFormat.indexOf(";") + 1); + offset = -offset; + } + hourFormat = hourFormat + .replaceFirst("H+", (isShort ? "\\%1\\$d" : "\\%1\\$02d")) + .replaceFirst("m+", "\\%2\\$02d"); + return MessageFormat.format(gmtFormat, + String.format(hourFormat, offset / 60, offset % 60)); + } + } +} diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index de0cd3aa473..ae9a1cf0aae 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R private volatile CurrencyNameProvider currencyNameProvider; private volatile LocaleNameProvider localeNameProvider; - private volatile TimeZoneNameProvider timeZoneNameProvider; + protected volatile TimeZoneNameProvider timeZoneNameProvider; protected volatile CalendarDataProvider calendarDataProvider; private volatile CalendarNameProvider calendarNameProvider; diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java index fa104df60b8..a42b8dda7b5 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java @@ -50,11 +50,12 @@ public interface LocaleDataMetaInfo { public String availableLanguageTags(String category); /** - * Returns a map for short time zone ids in BCP47 Unicode extension and - * the long time zone ids. - * @return map of short id to long ids, separated by a space. + * Returns a map for time zone ids to their canonical ids. + * The map key is either an LDML's short id, or a valid + * TZDB zone id. + * @return map of ids to their canonical ids. */ - default public Map tzShortIDs() { + default public Map tzCanonicalIDs() { return null; } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index 533eb315992..c0e817abecf 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import sun.security.action.GetPropertyAction; import sun.util.calendar.ZoneInfo; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; @@ -87,6 +88,9 @@ public class LocaleResources { private static final String NUMBER_PATTERNS_CACHEKEY = "NP"; private static final String DATE_TIME_PATTERN = "DTP."; + // TimeZoneNamesBundle exemplar city prefix + private static final String TZNB_EXCITY_PREFIX = "timezone.excity."; + // null singleton cache value private static final Object NULLOBJECT = new Object(); @@ -254,23 +258,32 @@ public class LocaleResources { return (String) localeName; } - String[] getTimeZoneNames(String key) { - String[] names = null; - String cacheKey = TIME_ZONE_NAMES + '.' + key; + public Object getTimeZoneNames(String key) { + Object val = null; + String cacheKey = TIME_ZONE_NAMES + key; removeEmptyReferences(); ResourceReference data = cache.get(cacheKey); - if (Objects.isNull(data) || Objects.isNull((names = (String[]) data.get()))) { + if (Objects.isNull(data) || Objects.isNull(val = data.get())) { TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); if (tznb.containsKey(key)) { - names = tznb.getStringArray(key); + if (key.startsWith(TZNB_EXCITY_PREFIX)) { + val = tznb.getString(key); + assert val instanceof String; + trace("tznb: %s key: %s, val: %s\n", tznb, key, val); + } else { + String[] names = tznb.getStringArray(key); + trace("tznb: %s key: %s, names: %s, %s, %s, %s, %s, %s, %s\n", tznb, key, + names[0], names[1], names[2], names[3], names[4], names[5], names[6]); + val = names; + } cache.put(cacheKey, - new ResourceReference(cacheKey, (Object) names, referenceQueue)); + new ResourceReference(cacheKey, val, referenceQueue)); } } - return names; + return val; } @SuppressWarnings("unchecked") @@ -296,7 +309,9 @@ public class LocaleResources { // Use a LinkedHashSet to preseve the order Set value = new LinkedHashSet<>(); for (String key : keyset) { - value.add(rb.getStringArray(key)); + if (!key.startsWith(TZNB_EXCITY_PREFIX)) { + value.add(rb.getStringArray(key)); + } } // Add aliases data for CLDR @@ -514,4 +529,13 @@ public class LocaleResources { return cacheKey; } } + + private static final boolean TRACE_ON = Boolean.valueOf( + GetPropertyAction.privilegedGetProperty("locale.resources.debug", "false")); + + public static void trace(String format, Object... params) { + if (TRACE_ON) { + System.out.format(format, params); + } + } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java index b0b4b7ae3cf..e5370b501aa 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java +++ b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.spi.TimeZoneNameProvider; -import sun.util.calendar.ZoneInfoFile; /** * Concrete implementation of the @@ -43,9 +42,8 @@ import sun.util.calendar.ZoneInfoFile; public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { private final LocaleProviderAdapter.Type type; private final Set langtags; - private static final String CLDR_NO_INHERITANCE_MARKER = "\u2205\u2205\u2205"; - TimeZoneNameProviderImpl(LocaleProviderAdapter.Type type, Set langtags) { + protected TimeZoneNameProviderImpl(LocaleProviderAdapter.Type type, Set langtags) { this.type = type; this.langtags = langtags; } @@ -120,41 +118,23 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { return null; } - private String[] getDisplayNameArray(String id, Locale locale) { + protected String[] getDisplayNameArray(String id, Locale locale) { Objects.requireNonNull(id); Objects.requireNonNull(locale); - String[] ret = - LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id); - - if (Objects.nonNull(ret) && type == LocaleProviderAdapter.Type.CLDR) { - // check for CLDR's "no inheritance marker" - for (int index = 0; index < ret.length; index++) { - TimeZone tz = null; - if (CLDR_NO_INHERITANCE_MARKER.equals(ret[index])) { - if (Objects.isNull(tz)) { - tz = TimeZone.getTimeZone(id); - } - int offset = tz.getRawOffset(); - if (index == 3 || index == 4) { // daylight - offset += tz.getDSTSavings(); - } - ret[index] = ZoneInfoFile.toCustomID(offset); - } - } - } - - return ret; + return (String []) LocaleProviderAdapter.forType(type) + .getLocaleResources(locale) + .getTimeZoneNames(id); } /** * Returns a String[][] as the DateFormatSymbols.getZoneStrings() value for - * the given locale. This method is package private. + * the given locale. * * @param locale a Locale for time zone names * @return an array of time zone names arrays */ - String[][] getZoneStrings(Locale locale) { + protected String[][] getZoneStrings(Locale locale) { return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getZoneStrings(); } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java index 57cfa1b05c6..f7e245c4e49 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java +++ b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -162,9 +162,15 @@ public final class TimeZoneNameUtility { * @return the tzdb's time zone ID */ public static Optional convertLDMLShortID(String shortID) { + return canonicalTZID(shortID); + } + + /** + * Returns the canonical ID for the given ID + */ + public static Optional canonicalTZID(String id) { return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) - .getTimeZoneID(shortID) - .map(id -> id.replaceAll("\\s.*", "")); + .canonicalTZID(id); } private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { diff --git a/src/java.base/share/classes/sun/util/resources/LocaleData.java b/src/java.base/share/classes/sun/util/resources/LocaleData.java index 497742667e7..429613413b8 100644 --- a/src/java.base/share/classes/sun/util/resources/LocaleData.java +++ b/src/java.base/share/classes/sun/util/resources/LocaleData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -275,11 +275,6 @@ public class LocaleData { } } } - // Force fallback to Locale.ENGLISH for CLDR time zone names support - if (locale.getLanguage() != "en" - && type == CLDR && category.equals("TimeZoneNames")) { - candidates.add(candidates.size() - 1, Locale.ENGLISH); - } CANDIDATES_MAP.putIfAbsent(key, candidates); } return candidates; diff --git a/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java index 2706efafe40..8a6fd8c52fd 100644 --- a/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java +++ b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,15 +79,16 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle { */ @Override public Object handleGetObject(String key) { - String[] contents = (String[]) super.handleGetObject(key); - if (Objects.isNull(contents)) { - return null; + Object val = super.handleGetObject(key); + if (val instanceof String[]) { + String[] contents = (String[]) val; + int clen = contents.length; + String[] tmpobj = new String[7]; + tmpobj[0] = key; + System.arraycopy(contents, 0, tmpobj, 1, clen); + return tmpobj; } - int clen = contents.length; - String[] tmpobj = new String[7]; - tmpobj[0] = key; - System.arraycopy(contents, 0, tmpobj, 1, clen); - return tmpobj; + return val; } /** diff --git a/test/jdk/java/util/TimeZone/Bug8149452.java b/test/jdk/java/util/TimeZone/Bug8149452.java index b73d65b1a7f..a70e82a0f91 100644 --- a/test/jdk/java/util/TimeZone/Bug8149452.java +++ b/test/jdk/java/util/TimeZone/Bug8149452.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8149452 8151876 + * @bug 8149452 8151876 8181157 * @summary Check the missing time zone names. */ import java.text.DateFormatSymbols; @@ -34,6 +34,20 @@ import java.util.List; public class Bug8149452 { public static void main(String[] args) { + // These zone ids are new in tzdb and yet to be reflected in + // CLDR data. Needs to be excluded from the test. + // This list is as of CLDR version 29, and should be examined + // on the CLDR data upgrade. + List NEW_ZONEIDS = List.of( + "America/Punta_Arenas", + "Asia/Atyrau", + "Asia/Barnaul", + "Asia/Famagusta", + "Asia/Tomsk", + "Europe/Astrakhan", + "Europe/Kirov", + "Europe/Saratov", + "Europe/Ulyanovsk"); List listNotFound = new ArrayList<>(); String[][] zoneStrings = DateFormatSymbols.getInstance() @@ -42,10 +56,9 @@ public class Bug8149452 { if (!Arrays.stream(zoneStrings) .anyMatch(zone -> tzID.equalsIgnoreCase(zone[0]))) { // to ignore names for Etc/GMT[+-][0-9]+ which are not supported - // Also ignore the TimeZone DisplayNames with GMT[+-]:hh:mm if (!tzID.startsWith("Etc/GMT") && !tzID.startsWith("GMT") - && !TimeZone.getTimeZone(tzID).getDisplayName().startsWith("GMT")) { + && !NEW_ZONEIDS.contains(tzID)) { listNotFound.add(tzID); } } diff --git a/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java b/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java index 4e092b41a50..c55cbfaf317 100644 --- a/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java +++ b/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8005471 8008577 8129881 8130845 8136518 + * @bug 8005471 8008577 8129881 8130845 8136518 8181157 * @modules jdk.localedata * @run main/othervm -Djava.locale.providers=CLDR CLDRDisplayNamesTest * @summary Make sure that localized time zone names of CLDR are used @@ -47,27 +47,27 @@ public class CLDRDisplayNamesTest { { "ja-JP", "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6a19\u6e96\u6642", - "PST", + "GMT-08:00", "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u590f\u6642\u9593", - "PDT", + "GMT-07:00", //"\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6642\u9593", //"PT" }, { "zh-CN", "\u5317\u7f8e\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4", - "PST", + "GMT-08:00", "\u5317\u7f8e\u592a\u5e73\u6d0b\u590f\u4ee4\u65f6\u95f4", - "PDT", + "GMT-07:00", //"\u5317\u7f8e\u592a\u5e73\u6d0b\u65f6\u95f4", //"PT", }, { "de-DE", "Nordamerikanische Westk\u00fcsten-Normalzeit", - "PST", + "GMT-08:00", "Nordamerikanische Westk\u00fcsten-Sommerzeit", - "PDT", + "GMT-07:00", //"Nordamerikanische Westk\u00fcstenzeit", //"PT", }, diff --git a/test/jdk/java/util/TimeZone/TimeZoneTest.java b/test/jdk/java/util/TimeZone/TimeZoneTest.java index 452c3af9f69..976958f078e 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/TimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 4028006 4044013 4096694 4107276 4107570 4112869 4130885 7039469 7126465 7158483 - * 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875 + * 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875 8181157 * @modules java.base/sun.util.resources * @library /java/text/testlib * @summary test TimeZone @@ -364,6 +364,7 @@ public class TimeZoneTest extends IntlTest } else if (!name.equals("Pacific Standard Time") && !name.equals("\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4") && + !name.equals("\u5317\u7f8e\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4") && !name.equals("GMT-08:00") && !name.equals("GMT-8:00") && !name.equals("GMT-0800") && diff --git a/test/jdk/sun/text/resources/LocaleData.cldr b/test/jdk/sun/text/resources/LocaleData.cldr index 2d368167a23..8659cbc660e 100644 --- a/test/jdk/sun/text/resources/LocaleData.cldr +++ b/test/jdk/sun/text/resources/LocaleData.cldr @@ -5563,7 +5563,7 @@ FormatData/fi/AmPmMarkers/1=ip. # bug 6507067 TimeZoneNames/zh_TW/Asia\/Taipei/1=\u53f0\u5317\u6a19\u6e96\u6642\u9593 -TimeZoneNames/zh_TW/Asia\/Taipei/2=CST +TimeZoneNames/zh_TW/Asia\/Taipei/2= # bug 6645271 FormatData/hr_HR/DatePatterns/2=d. MMM y. diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index c39c3182bb6..a2ddaa0cc7f 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ * 7114053 7074882 7040556 8008577 8013836 8021121 6192407 6931564 8027695 * 8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361 8134916 * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 - * 8187946 8195478 + * 8187946 8195478 8181157 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java new file mode 100644 index 00000000000..25f155f09a5 --- /dev/null +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 8181157 + * @modules jdk.localedata + * @summary Checks CLDR time zone names are generated correctly at runtime + * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest + */ + +import static org.testng.Assert.assertEquals; + +import java.time.ZoneId; +import java.time.format.TextStyle; +import java.util.Locale; +import java.util.TimeZone; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +@Test +public class TimeZoneNamesTest { + + @DataProvider(name="noResourceTZs") + Object[][] data() { + return new Object[][] { + // tzid, locale, style, expected + + // These zone ids are new in tzdb and yet to be reflected in + // CLDR data. Thus it's assured there is no l10n names for these. + // This list is as of CLDR version 29, and should be examined + // on the CLDR data upgrade. + {"America/Punta_Arenas", Locale.US, "Punta Arenas Standard Time", + "GMT-03:00", + "Punta Arenas Daylight Time", + "GMT-03:00", + "Punta Arenas Time", + "GMT-03:00"}, + {"America/Punta_Arenas", Locale.FRANCE, "Punta Arenas (heure standard)", + "UTC\u221203:00", + "Punta Arenas (heure d\u2019\u00e9t\u00e9)", + "UTC\u221203:00", + "heure : Punta Arenas", + "UTC\u221203:00"}, + {"Asia/Atyrau", Locale.US, "Atyrau Standard Time", + "GMT+05:00", + "Atyrau Daylight Time", + "GMT+05:00", + "Atyrau Time", + "GMT+05:00"}, + {"Asia/Atyrau", Locale.FRANCE, "Atyrau (heure standard)", + "UTC+05:00", + "Atyrau (heure d\u2019\u00e9t\u00e9)", + "UTC+05:00", + "heure : Atyrau", + "UTC+05:00"}, + + // no "metazone" zones + {"Asia/Srednekolymsk", Locale.US, "Srednekolymsk Time", + "SRET", + "Srednekolymsk Daylight Time", + "SREDT", + "Srednekolymsk Time", + "SRET"}, + {"Asia/Srednekolymsk", Locale.FRANCE, "Srednekolymsk (heure standard)", + "UTC+11:00", + "Srednekolymsk (heure standard)", + "UTC+11:00", + "heure : Srednekolymsk", + "UTC+11:00"}, + {"Pacific/Bougainville", Locale.US, "Bougainville Standard Time", + "BST", + "Bougainville Daylight Time", + "BST", + "Bougainville Time", + "BT"}, + {"Pacific/Bougainville", Locale.FRANCE, "Bougainville (heure standard)", + "UTC+11:00", + "Bougainville (heure standard)", + "UTC+11:00", + "heure : Bougainville", + "UTC+11:00"}, + + }; + } + + + @Test(dataProvider="noResourceTZs") + public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, String ldst, String sdst, String lgen, String sgen) { + // Standard time + assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale), lstd); + assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.SHORT, locale), sstd); + + // daylight saving time + assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.LONG, locale), ldst); + assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.SHORT, locale), sdst); + + // generic name + assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale), lgen); + assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale), sgen); + } +} From 0ef11c31c73a9e8aa4f0ba6e8ed423de1ff8ff65 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 26 Apr 2018 12:48:35 -0700 Subject: [PATCH 060/102] 8201367: assert(current != first_mem) failed: corrupted memory graph in superword code Don't rely on the RPO order to find the "first" and "last" loads of the pack Reviewed-by: kvn --- src/hotspot/share/opto/superword.cpp | 17 ++++++- .../TestUnexpectedLoadOrdering.java | 51 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestUnexpectedLoadOrdering.java diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index f6c4162a60e..5026ee315e9 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2144,8 +2144,21 @@ void SuperWord::co_locate_pack(Node_List* pk) { // we use the memory state of the last load. However, if any load could // not be moved down due to the dependence constraint, we use the memory // state of the first load. - Node* last_mem = executed_last(pk)->in(MemNode::Memory); - Node* first_mem = executed_first(pk)->in(MemNode::Memory); + Node* first_mem = pk->at(0)->in(MemNode::Memory); + Node* last_mem = first_mem; + for (uint i = 1; i < pk->size(); i++) { + Node* ld = pk->at(i); + Node* mem = ld->in(MemNode::Memory); + assert(in_bb(first_mem) || in_bb(mem) || mem == first_mem, "2 different memory state from outside the loop?"); + if (in_bb(mem)) { + if (in_bb(first_mem) && bb_idx(mem) < bb_idx(first_mem)) { + first_mem = mem; + } + if (!in_bb(last_mem) || bb_idx(mem) > bb_idx(last_mem)) { + last_mem = mem; + } + } + } bool schedule_last = true; for (uint i = 0; i < pk->size(); i++) { Node* ld = pk->at(i); diff --git a/test/hotspot/jtreg/compiler/vectorization/TestUnexpectedLoadOrdering.java b/test/hotspot/jtreg/compiler/vectorization/TestUnexpectedLoadOrdering.java new file mode 100644 index 00000000000..4e946c113bb --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestUnexpectedLoadOrdering.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 8201367 + * @summary RPO walk of counted loop block doesn't properly order loads + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseCountedLoopSafepoints TestUnexpectedLoadOrdering + * + */ + +public class TestUnexpectedLoadOrdering { + + public static void main(String[] args) { + double[] array1 = new double[1000]; + double[] array2 = new double[1000]; + for (int i = 0; i < 20_000; i++) { + test(array1, array2); + } + } + + private static double test(double[] array1, double[] array2) { + double res = 0; + for (int i = 0; i < array1.length; i++) { + array2[i] = i; + res += array1[i]; + } + return res; + } +} From f4893f5a9a5d9d532c1a651b2633f15702fd8be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Thu, 26 Apr 2018 20:42:43 +0200 Subject: [PATCH 061/102] 8201543: Modularize C1 GC barriers Reviewed-by: pliden, rbackman, rkennke --- make/hotspot/lib/JvmFeatures.gmk | 2 +- .../cpu/aarch64/c1_CodeStubs_aarch64.cpp | 41 -- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 11 +- .../cpu/aarch64/c1_LIRGenerator_aarch64.cpp | 293 ++------ .../cpu/aarch64/c1_MacroAssembler_aarch64.cpp | 12 +- .../cpu/aarch64/c1_MacroAssembler_aarch64.hpp | 4 +- .../cpu/aarch64/c1_Runtime1_aarch64.cpp | 158 +--- .../gc/g1/g1BarrierSetAssembler_aarch64.cpp | 166 +++++ .../gc/g1/g1BarrierSetAssembler_aarch64.hpp | 14 + src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp | 44 -- src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp | 261 +------ src/hotspot/cpu/arm/c1_Runtime1_arm.cpp | 207 +----- .../arm/gc/g1/g1BarrierSetAssembler_arm.cpp | 245 ++++++ .../arm/gc/g1/g1BarrierSetAssembler_arm.hpp | 14 + src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp | 57 -- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 4 +- src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp | 302 ++------ src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp | 164 ----- .../ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp | 212 +++++- .../ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp | 14 + src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp | 45 -- src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 181 +++-- src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp | 232 ++---- src/hotspot/cpu/s390/c1_Runtime1_s390.cpp | 174 ----- .../s390/gc/g1/g1BarrierSetAssembler_s390.cpp | 210 ++++++ .../s390/gc/g1/g1BarrierSetAssembler_s390.hpp | 14 + src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp | 62 -- .../cpu/sparc/c1_LIRGenerator_sparc.cpp | 259 ++----- .../cpu/sparc/c1_MacroAssembler_sparc.hpp | 5 +- src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp | 194 +---- .../gc/g1/g1BarrierSetAssembler_sparc.cpp | 217 +++++- .../gc/g1/g1BarrierSetAssembler_sparc.hpp | 14 + src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp | 44 -- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 340 ++------- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 9 + src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp | 7 +- src/hotspot/cpu/x86/c1_Runtime1_x86.cpp | 215 +----- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 195 +++++ .../x86/gc/g1/g1BarrierSetAssembler_x86.hpp | 11 + src/hotspot/share/c1/c1_CodeStubs.hpp | 90 +-- src/hotspot/share/c1/c1_Decorators.hpp | 42 ++ src/hotspot/share/c1/c1_LIRAssembler.hpp | 4 +- src/hotspot/share/c1/c1_LIRGenerator.cpp | 695 ++++++------------ src/hotspot/share/c1/c1_LIRGenerator.hpp | 73 +- src/hotspot/share/c1/c1_MacroAssembler.hpp | 6 + src/hotspot/share/c1/c1_Runtime1.cpp | 74 +- src/hotspot/share/c1/c1_Runtime1.hpp | 12 +- src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp | 230 ++++++ src/hotspot/share/gc/g1/c1/g1BarrierSetC1.hpp | 138 ++++ src/hotspot/share/gc/g1/g1BarrierSet.cpp | 6 + src/hotspot/share/gc/shared/barrierSet.hpp | 21 +- .../share/gc/shared/c1/barrierSetC1.cpp | 326 ++++++++ .../share/gc/shared/c1/barrierSetC1.hpp | 139 ++++ .../gc/shared/c1/cardTableBarrierSetC1.cpp | 102 +++ .../gc/shared/c1/cardTableBarrierSetC1.hpp | 35 + .../share/gc/shared/c1/modRefBarrierSetC1.cpp | 92 +++ .../share/gc/shared/c1/modRefBarrierSetC1.hpp | 50 ++ .../share/gc/shared/cardTableBarrierSet.cpp | 8 + .../share/gc/shared/cardTableBarrierSet.hpp | 1 + .../share/gc/shared/modRefBarrierSet.hpp | 2 + src/hotspot/share/oops/accessBackend.hpp | 25 - src/hotspot/share/oops/accessDecorators.hpp | 59 ++ src/hotspot/share/utilities/macros.hpp | 2 + 63 files changed, 3484 insertions(+), 3401 deletions(-) create mode 100644 src/hotspot/share/c1/c1_Decorators.hpp create mode 100644 src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp create mode 100644 src/hotspot/share/gc/g1/c1/g1BarrierSetC1.hpp create mode 100644 src/hotspot/share/gc/shared/c1/barrierSetC1.cpp create mode 100644 src/hotspot/share/gc/shared/c1/barrierSetC1.hpp create mode 100644 src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp create mode 100644 src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.hpp create mode 100644 src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.cpp create mode 100644 src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.hpp diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index 09d868ded79..454695b2685 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -32,7 +32,7 @@ $(eval $(call IncludeCustomExtension, hotspot/lib/JvmFeatures.gmk)) ifeq ($(call check-jvm-feature, compiler1), true) JVM_CFLAGS_FEATURES += -DCOMPILER1 else - JVM_EXCLUDE_PATTERNS += c1_ + JVM_EXCLUDE_PATTERNS += c1_ c1/ endif ifeq ($(call check-jvm-feature, compiler2), true) diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp index 66d7a8bc5fd..99f2319e06e 100644 --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -32,9 +32,6 @@ #include "nativeInst_aarch64.hpp" #include "runtime/sharedRuntime.hpp" #include "vmreg_aarch64.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#endif #define __ ce->masm()-> @@ -350,42 +347,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ b(_continuation); } - -///////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that marking is in progress. - // If do_load() is true then we have to emit the - // load of the previous value; otherwise it has already - // been loaded into _pre_val. - - __ bind(_entry); - assert(pre_val()->is_register(), "Precondition."); - - Register pre_val_reg = pre_val()->as_register(); - - if (do_load()) { - ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); - } - __ cbz(pre_val_reg, _continuation); - ce->store_parameter(pre_val()->as_register(), 0); - __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id))); - __ b(_continuation); -} - -void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - assert(addr()->is_register(), "Precondition."); - assert(new_val()->is_register(), "Precondition."); - Register new_val_reg = new_val()->as_register(); - __ cbz(new_val_reg, _continuation); - ce->store_parameter(addr()->as_pointer_register(), 0); - __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id))); - __ b(_continuation); -} - -#endif // INCLUDE_ALL_GCS -///////////////////////////////////////////////////////////////////////////// - #undef __ diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 9d8e6ec4307..f874e22a581 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1558,7 +1558,16 @@ void LIR_Assembler::casl(Register addr, Register newval, Register cmpval) { void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { assert(VM_Version::supports_cx8(), "wrong machine"); - Register addr = as_reg(op->addr()); + Register addr; + if (op->addr()->is_register()) { + addr = as_reg(op->addr()); + } else { + assert(op->addr()->is_address(), "what else?"); + LIR_Address* addr_ptr = op->addr()->as_address_ptr(); + assert(addr_ptr->disp() == 0, "need 0 disp"); + assert(addr_ptr->index() == LIR_OprDesc::illegalOpr(), "need 0 index"); + addr = as_reg(addr_ptr->base()); + } Register newval = as_reg(op->new_value()); Register cmpval = as_reg(op->cmp_value()); Label succeed, fail, around; diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index c7c4d2dad99..caadd0fb908 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -144,8 +144,22 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, // accumulate fixed displacements if (index->is_constant()) { - large_disp += (intx)(index->as_constant_ptr()->as_jint()) << shift; - index = LIR_OprFact::illegalOpr; + LIR_Const *constant = index->as_constant_ptr(); + if (constant->type() == T_INT) { + large_disp += index->as_jint() << shift; + } else { + assert(constant->type() == T_LONG, "should be"); + jlong c = index->as_jlong() << shift; + if ((jlong)((jint)c) == c) { + large_disp += c; + index = LIR_OprFact::illegalOpr; + } else { + LIR_Opr tmp = new_register(T_LONG); + __ move(index, tmp); + index = tmp; + // apply shift and displacement below + } + } } if (index->is_register()) { @@ -183,9 +197,8 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, } } - LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type, bool needs_card_mark) { + BasicType type) { int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type); int elem_size = type2aelembytes(type); int shift = exact_log2(elem_size); @@ -206,16 +219,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o LIR_Address::scale(type), offset_in_bytes, type); } - if (needs_card_mark) { - // This store will need a precise card mark, so go ahead and - // compute the full adddres instead of computing once for the - // store and again for the card mark. - LIR_Opr tmp = new_pointer_register(); - __ leal(LIR_OprFact::address(addr), tmp); - return new LIR_Address(tmp, type); - } else { - return addr; - } + return addr; } LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { @@ -305,87 +309,17 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) __ store(item, new LIR_Address(FrameMap::sp_opr, in_bytes(offset_from_sp), type)); } -//---------------------------------------------------------------------- -// visitor functions -//---------------------------------------------------------------------- - - -void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { - assert(x->is_pinned(),""); - bool needs_range_check = x->compute_needs_range_check(); - bool use_length = x->length() != NULL; - bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || - !get_jobject_constant(x->value())->is_null_object() || - x->should_profile()); - - LIRItem array(x->array(), this); - LIRItem index(x->index(), this); - LIRItem value(x->value(), this); - LIRItem length(this); - - array.load_item(); - index.load_nonconstant(); - - if (use_length && needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - - } - if (needs_store_check || x->check_boolean()) { - value.load_item(); - } else { - value.load_for_store(x->elt_type()); - } - - set_no_result(x); - - // the CodeEmitInfo must be duplicated for each different - // LIR-instruction because spilling can occur anywhere between two - // instructions and so the debug information must be different - CodeEmitInfo* range_check_info = state_for(x); - CodeEmitInfo* null_check_info = NULL; - if (x->needs_null_check()) { - null_check_info = new CodeEmitInfo(range_check_info); - } - - // emit array address setup early so it schedules better - // FIXME? No harm in this on aarch64, and it might help - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); - - if (GenerateRangeChecks && needs_range_check) { - if (use_length) { - __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); - } else { - array_range_check(array.result(), index.result(), null_check_info, range_check_info); - // range_check also does the null check - null_check_info = NULL; - } - } - - if (GenerateArrayStoreCheck && needs_store_check) { +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { LIR_Opr tmp1 = new_register(objectType); LIR_Opr tmp2 = new_register(objectType); LIR_Opr tmp3 = new_register(objectType); - - CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); - __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci()); - } - - if (obj_store) { - // Needs GC write barriers. - pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - __ move(value.result(), array_addr, null_check_info); - // Seems to be a precise - post_barrier(LIR_OprFact::address(array_addr), value.result()); - } else { - LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); - __ move(result, array_addr, null_check_info); - } + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); } +//---------------------------------------------------------------------- +// visitor functions +//---------------------------------------------------------------------- + void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { assert(x->is_pinned(),""); LIRItem obj(x->obj(), this); @@ -771,76 +705,42 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { } } -void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { - assert(x->number_of_arguments() == 4, "wrong type"); - LIRItem obj (x->argument_at(0), this); // object - LIRItem offset(x->argument_at(1), this); // offset of field - LIRItem cmp (x->argument_at(2), this); // value to compare with field - LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp - - assert(obj.type()->tag() == objectTag, "invalid type"); - - // In 64bit the type can be long, sparc doesn't have this assert - // assert(offset.type()->tag() == intTag, "invalid type"); - - assert(cmp.type()->tag() == type->tag(), "invalid type"); - assert(val.type()->tag() == type->tag(), "invalid type"); - - // get address of field - obj.load_item(); - offset.load_nonconstant(); - val.load_item(); - cmp.load_item(); - - LIR_Address* a; - if(offset.result()->is_constant()) { - jlong c = offset.result()->as_jlong(); - if ((jlong)((jint)c) == c) { - a = new LIR_Address(obj.result(), - (jint)c, - as_BasicType(type)); - } else { - LIR_Opr tmp = new_register(T_LONG); - __ move(offset.result(), tmp); - a = new LIR_Address(obj.result(), - tmp, - as_BasicType(type)); - } - } else { - a = new LIR_Address(obj.result(), - offset.result(), - 0, - as_BasicType(type)); - } - LIR_Opr addr = new_pointer_register(); - __ leal(LIR_OprFact::address(a), addr); - - if (type == objectType) { // Write-barrier needed for Object fields. - // Do the pre-write barrier, if any. - pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - - LIR_Opr result = rlock_result(x); - +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience - if (type == objectType) - __ cas_obj(addr, cmp.result(), val.result(), new_register(T_INT), new_register(T_INT), - result); - else if (type == intType) - __ cas_int(addr, cmp.result(), val.result(), ill, ill); - else if (type == longType) - __ cas_long(addr, cmp.result(), val.result(), ill, ill); - else { + new_value.load_item(); + cmp_value.load_item(); + LIR_Opr result = new_register(T_INT); + if (type == T_OBJECT || type == T_ARRAY) { + __ cas_obj(addr, cmp_value.result(), new_value.result(), new_register(T_INT), new_register(T_INT), result); + } else if (type == T_INT) { + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else if (type == T_LONG) { + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else { ShouldNotReachHere(); + Unimplemented(); } - __ logical_xor(FrameMap::r8_opr, LIR_OprFact::intConst(1), result); + return result; +} - if (type == objectType) { // Write-barrier needed for Object fields. - // Seems to be precise - post_barrier(addr, val.result()); - } +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + bool is_oop = type == T_OBJECT || type == T_ARRAY; + LIR_Opr result = new_register(type); + value.load_item(); + assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp = new_register(T_INT); + __ xchg(addr, value.result(), result, tmp); + return result; +} + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + value.load_item(); + assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp = new_register(T_INT); + __ xadd(addr, value.result(), result, tmp); + return result; } void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { @@ -1433,84 +1333,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, __ volatile_load_mem_reg(address, result, info); } - -void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, - BasicType type, bool is_volatile) { - LIR_Address* addr = new LIR_Address(src, offset, type); - __ load(addr, dst); -} - - -void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, - BasicType type, bool is_volatile) { - LIR_Address* addr = new LIR_Address(src, offset, type); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - if (is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - __ move(data, addr); - assert(src->is_register(), "must be register"); - // Seems to be a precise address - post_barrier(LIR_OprFact::address(addr), data); - } else { - __ move(data, addr); - } -} - -void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { - BasicType type = x->basic_type(); - LIRItem src(x->object(), this); - LIRItem off(x->offset(), this); - LIRItem value(x->value(), this); - - src.load_item(); - off.load_nonconstant(); - - // We can cope with a constant increment in an xadd - if (! (x->is_add() - && value.is_constant() - && can_inline_as_constant(x->value()))) { - value.load_item(); - } - - LIR_Opr dst = rlock_result(x, type); - LIR_Opr data = value.result(); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - LIR_Opr offset = off.result(); - - if (data == dst) { - LIR_Opr tmp = new_register(data->type()); - __ move(data, tmp); - data = tmp; - } - - LIR_Address* addr; - if (offset->is_constant()) { - jlong l = offset->as_jlong(); - assert((jlong)((jint)l) == l, "offset too large for constant"); - jint c = (jint)l; - addr = new LIR_Address(src.result(), c, type); - } else { - addr = new LIR_Address(src.result(), offset, type); - } - - LIR_Opr tmp = new_register(T_INT); - LIR_Opr ptr = LIR_OprFact::illegalOpr; - - if (x->is_add()) { - __ xadd(LIR_OprFact::address(addr), data, dst, tmp); - } else { - if (is_obj) { - // Do the pre-write barrier, if any. - ptr = new_pointer_register(); - __ add(src.result(), off.result(), ptr); - pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - __ xchg(LIR_OprFact::address(addr), data, dst, tmp); - if (is_obj) { - post_barrier(ptr, data); - } - } -} diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 47fda46dd23..da0555420de 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -358,6 +358,16 @@ void C1_MacroAssembler::remove_frame(int framesize) { void C1_MacroAssembler::verified_entry() { } +void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) { + // rbp, + 0: link + // + 1: return address + // + 2: argument with offset 0 + // + 3: argument with offset 1 + // + 4: ... + + ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord)); +} + #ifndef PRODUCT void C1_MacroAssembler::verify_stack_oop(int stack_offset) { diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp index 490e22507b6..932a11bc194 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -109,4 +109,6 @@ using MacroAssembler::null_check; // This platform only uses signal-based null checks. The Label is not needed. void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); } + void load_parameter(int offset_in_words, Register reg); + #endif // CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index ad09fb39295..e6ebb7f715c 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -43,11 +43,6 @@ #include "runtime/vframe.hpp" #include "runtime/vframeArray.hpp" #include "vmreg_aarch64.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#endif // Implementation of StubAssembler @@ -173,31 +168,32 @@ class StubFrame: public StackObj { ~StubFrame(); };; +void StubAssembler::prologue(const char* name, bool must_gc_arguments) { + set_info(name, must_gc_arguments); + enter(); +} + +void StubAssembler::epilogue() { + leave(); + ret(lr); +} #define __ _sasm-> StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) { _sasm = sasm; - __ set_info(name, must_gc_arguments); - __ enter(); + __ prologue(name, must_gc_arguments); } // load parameters that were stored with LIR_Assembler::store_parameter // Note: offsets for store_parameter and load_argument must match void StubFrame::load_argument(int offset_in_words, Register reg) { - // rbp, + 0: link - // + 1: return address - // + 2: argument with offset 0 - // + 3: argument with offset 1 - // + 4: ... - - __ ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord)); + __ load_parameter(offset_in_words, reg); } StubFrame::~StubFrame() { - __ leave(); - __ ret(lr); + __ epilogue(); } #undef __ @@ -1100,136 +1096,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#if INCLUDE_ALL_GCS - - case g1_pre_barrier_slow_id: - { - StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments); - // arg0 : previous value of memory - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ mov(r0, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), r0); - __ should_not_reach_here(); - break; - } - - const Register pre_val = r0; - const Register thread = rthread; - const Register tmp = rscratch1; - - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - Label done; - Label runtime; - - // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ldrw(tmp, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldrb(tmp, in_progress); - } - __ cbzw(tmp, done); - - // Can we store original value in the thread's buffer? - __ ldr(tmp, queue_index); - __ cbz(tmp, runtime); - - __ sub(tmp, tmp, wordSize); - __ str(tmp, queue_index); - __ ldr(rscratch2, buffer); - __ add(tmp, tmp, rscratch2); - f.load_argument(0, rscratch2); - __ str(rscratch2, Address(tmp, 0)); - __ b(done); - - __ bind(runtime); - __ push_call_clobbered_registers(); - f.load_argument(0, pre_val); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread); - __ pop_call_clobbered_registers(); - __ bind(done); - } - break; - case g1_post_barrier_slow_id: - { - StubFrame f(sasm, "g1_post_barrier", dont_gc_arguments); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ mov(r0, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), r0); - __ should_not_reach_here(); - break; - } - - // arg0: store_address - Address store_addr(rfp, 2*BytesPerWord); - - Label done; - Label runtime; - - // At this point we know new_value is non-NULL and the new_value crosses regions. - // Must check to see if card is already dirty - - const Register thread = rthread; - - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - const Register card_offset = rscratch2; - // LR is free here, so we can use it to hold the byte_map_base. - const Register byte_map_base = lr; - - assert_different_registers(card_offset, byte_map_base, rscratch1); - - f.load_argument(0, card_offset); - __ lsr(card_offset, card_offset, CardTable::card_shift); - __ load_byte_map_base(byte_map_base); - __ ldrb(rscratch1, Address(byte_map_base, card_offset)); - __ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val()); - __ br(Assembler::EQ, done); - - assert((int)CardTable::dirty_card_val() == 0, "must be 0"); - - __ membar(Assembler::StoreLoad); - __ ldrb(rscratch1, Address(byte_map_base, card_offset)); - __ cbzw(rscratch1, done); - - // storing region crossing non-NULL, card is clean. - // dirty card and log. - __ strb(zr, Address(byte_map_base, card_offset)); - - // Convert card offset into an address in card_addr - Register card_addr = card_offset; - __ add(card_addr, byte_map_base, card_addr); - - __ ldr(rscratch1, queue_index); - __ cbz(rscratch1, runtime); - __ sub(rscratch1, rscratch1, wordSize); - __ str(rscratch1, queue_index); - - // Reuse LR to hold buffer_addr - const Register buffer_addr = lr; - - __ ldr(buffer_addr, buffer); - __ str(card_addr, Address(buffer_addr, rscratch1)); - __ b(done); - - __ bind(runtime); - __ push_call_clobbered_registers(); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread); - __ pop_call_clobbered_registers(); - __ bind(done); - - } - break; -#endif - case predicate_failed_trap_id: { StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments); diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp index 8e2af097b49..21ec91db4e5 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp @@ -24,6 +24,9 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1CardTable.hpp" @@ -307,4 +310,167 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco } +#ifdef COMPILER1 + #undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(*stub->entry()); + + assert(stub->pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); + } + __ cbz(pre_val_reg, *stub->continuation()); + ce->store_parameter(stub->pre_val()->as_register(), 0); + __ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + assert(stub->addr()->is_register(), "Precondition."); + assert(stub->new_val()->is_register(), "Precondition."); + Register new_val_reg = stub->new_val()->as_register(); + __ cbz(new_val_reg, *stub->continuation()); + ce->store_parameter(stub->addr()->as_pointer_register(), 0); + __ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin())); + __ b(*stub->continuation()); +} + +#undef __ + +#define __ sasm-> + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_pre_barrier", false); + + // arg0 : previous value of memory + + BarrierSet* bs = BarrierSet::barrier_set(); + + const Register pre_val = r0; + const Register thread = rthread; + const Register tmp = rscratch1; + + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + Label done; + Label runtime; + + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ldrw(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(tmp, in_progress); + } + __ cbzw(tmp, done); + + // Can we store original value in the thread's buffer? + __ ldr(tmp, queue_index); + __ cbz(tmp, runtime); + + __ sub(tmp, tmp, wordSize); + __ str(tmp, queue_index); + __ ldr(rscratch2, buffer); + __ add(tmp, tmp, rscratch2); + __ load_parameter(0, rscratch2); + __ str(rscratch2, Address(tmp, 0)); + __ b(done); + + __ bind(runtime); + __ push_call_clobbered_registers(); + __ load_parameter(0, pre_val); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread); + __ pop_call_clobbered_registers(); + __ bind(done); + + __ epilogue(); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_post_barrier", false); + + // arg0: store_address + Address store_addr(rfp, 2*BytesPerWord); + + BarrierSet* bs = BarrierSet::barrier_set(); + CardTableBarrierSet* ctbs = barrier_set_cast(bs); + CardTable* ct = ctbs->card_table(); + assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code"); + + Label done; + Label runtime; + + // At this point we know new_value is non-NULL and the new_value crosses regions. + // Must check to see if card is already dirty + + const Register thread = rthread; + + Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); + + const Register card_offset = rscratch2; + // LR is free here, so we can use it to hold the byte_map_base. + const Register byte_map_base = lr; + + assert_different_registers(card_offset, byte_map_base, rscratch1); + + __ load_parameter(0, card_offset); + __ lsr(card_offset, card_offset, CardTable::card_shift); + __ load_byte_map_base(byte_map_base); + __ ldrb(rscratch1, Address(byte_map_base, card_offset)); + __ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val()); + __ br(Assembler::EQ, done); + + assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + + __ membar(Assembler::StoreLoad); + __ ldrb(rscratch1, Address(byte_map_base, card_offset)); + __ cbzw(rscratch1, done); + + // storing region crossing non-NULL, card is clean. + // dirty card and log. + __ strb(zr, Address(byte_map_base, card_offset)); + + // Convert card offset into an address in card_addr + Register card_addr = card_offset; + __ add(card_addr, byte_map_base, card_addr); + + __ ldr(rscratch1, queue_index); + __ cbz(rscratch1, runtime); + __ sub(rscratch1, rscratch1, wordSize); + __ str(rscratch1, queue_index); + + // Reuse LR to hold buffer_addr + const Register buffer_addr = lr; + + __ ldr(buffer_addr, buffer); + __ str(card_addr, Address(buffer_addr, rscratch1)); + __ b(done); + + __ bind(runtime); + __ push_call_clobbered_registers(); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread); + __ pop_call_clobbered_registers(); + __ bind(done); + __ epilogue(); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp index d6e942f2976..965fd06b517 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp @@ -27,6 +27,12 @@ #include "asm/macroAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "utilities/macros.hpp" + +class LIR_Assembler; +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -54,6 +60,14 @@ protected: Address dst, Register val, Register tmp1, Register tmp2); public: +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); +#endif + void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); }; diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp index b9d961df291..5c4caff1778 100644 --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -33,9 +33,6 @@ #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" #include "vmreg_arm.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -466,45 +463,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ b(_continuation); } -///////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that marking is in progress. - // If do_load() is true then we have to emit the - // load of the previous value; otherwise it has already - // been loaded into _pre_val. - - __ bind(_entry); - assert(pre_val()->is_register(), "Precondition."); - - Register pre_val_reg = pre_val()->as_register(); - - if (do_load()) { - ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); - } - - __ cbz(pre_val_reg, _continuation); - ce->verify_reserved_argument_area_size(1); - __ str(pre_val_reg, Address(SP)); - __ call(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id), relocInfo::runtime_call_type); - - __ b(_continuation); -} - -void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - assert(addr()->is_register(), "Precondition."); - assert(new_val()->is_register(), "Precondition."); - Register new_val_reg = new_val()->as_register(); - __ cbz(new_val_reg, _continuation); - ce->verify_reserved_argument_area_size(1); - __ str(addr()->as_pointer_register(), Address(SP)); - __ call(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id), relocInfo::runtime_call_type); - __ b(_continuation); -} - -#endif // INCLUDE_ALL_GCS -///////////////////////////////////////////////////////////////////////////// - #undef __ diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index d8a6c465599..c03eb66281f 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -34,6 +34,7 @@ #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" #include "ci/ciUtilities.hpp" +#include "gc/shared/c1/barrierSetC1.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "runtime/sharedRuntime.hpp" @@ -542,88 +543,17 @@ void LIRGenerator::CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LI } } +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { + LIR_Opr tmp1 = FrameMap::R0_oop_opr; + LIR_Opr tmp2 = FrameMap::R1_oop_opr; + LIR_Opr tmp3 = LIR_OprFact::illegalOpr; + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); +} + //---------------------------------------------------------------------- // visitor functions //---------------------------------------------------------------------- - -void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { - assert(x->is_pinned(),""); - bool needs_range_check = x->compute_needs_range_check(); - bool use_length = x->length() != NULL; - bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || - !get_jobject_constant(x->value())->is_null_object() || - x->should_profile()); - - LIRItem array(x->array(), this); - LIRItem index(x->index(), this); - LIRItem value(x->value(), this); - LIRItem length(this); - - array.load_item(); - index.load_nonconstant(); - - if (use_length && needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } - if (needs_store_check || x->check_boolean()) { - value.load_item(); - } else { - value.load_for_store(x->elt_type()); - } - - set_no_result(x); - - // the CodeEmitInfo must be duplicated for each different - // LIR-instruction because spilling can occur anywhere between two - // instructions and so the debug information must be different - CodeEmitInfo* range_check_info = state_for(x); - CodeEmitInfo* null_check_info = NULL; - if (x->needs_null_check()) { - null_check_info = new CodeEmitInfo(range_check_info); - } - - // emit array address setup early so it schedules better - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); - - if (GenerateRangeChecks && needs_range_check) { - if (use_length) { - __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); - } else { - array_range_check(array.result(), index.result(), null_check_info, range_check_info); - // range_check also does the null check - null_check_info = NULL; - } - } - - if (GenerateArrayStoreCheck && needs_store_check) { - LIR_Opr tmp1 = FrameMap::R0_oop_opr; - LIR_Opr tmp2 = FrameMap::R1_oop_opr; - CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); - __ store_check(value.result(), array.result(), tmp1, tmp2, - LIR_OprFact::illegalOpr, store_check_info, - x->profiled_method(), x->profiled_bci()); - } - -#if INCLUDE_ALL_GCS - if (obj_store) { - // Needs GC write barriers. - pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } -#endif // INCLUDE_ALL_GCS - - LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); - __ move(result, array_addr, null_check_info); - if (obj_store) { - post_barrier(LIR_OprFact::address(array_addr), value.result()); - } -} - - void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { assert(x->is_pinned(),""); LIRItem obj(x->obj(), this); @@ -1060,56 +990,52 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { #endif // __SOFTFP__ } - -void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { - assert(x->number_of_arguments() == 4, "wrong type"); - LIRItem obj (x->argument_at(0), this); // object - LIRItem offset(x->argument_at(1), this); // offset of field - LIRItem cmp (x->argument_at(2), this); // value to compare with field - LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp - - LIR_Opr addr = new_pointer_register(); +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { + LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience LIR_Opr tmp1 = LIR_OprFact::illegalOpr; LIR_Opr tmp2 = LIR_OprFact::illegalOpr; - - // get address of field - obj.load_item(); - offset.load_item(); - cmp.load_item(); - val.load_item(); - - __ add(obj.result(), offset.result(), addr); - LIR_Opr result = rlock_result(x); - - if (type == objectType) { -#if INCLUDE_ALL_GCS - // Do the pre-write barrier, if any. - pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); -#endif // INCLUDE_ALL_GCS + new_value.load_item(); + cmp_value.load_item(); + LIR_Opr result = new_register(T_INT); + if (type == T_OBJECT || type == T_ARRAY) { #ifdef AARCH64 if (UseCompressedOops) { tmp1 = new_pointer_register(); tmp2 = new_pointer_register(); } -#endif // AARCH64 - __ cas_obj(addr, cmp.result(), val.result(), tmp1, tmp2, result); - post_barrier(addr, val.result()); - } - else if (type == intType) { - __ cas_int(addr, cmp.result(), val.result(), tmp1, tmp1, result); - } - else if (type == longType) { +#endif + __ cas_obj(addr, cmp_value.result(), new_value.result(), new_register(T_INT), new_register(T_INT), result); + } else if (type == T_INT) { + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), tmp1, tmp1, result); + } else if (type == T_LONG) { #ifndef AARCH64 tmp1 = new_register(T_LONG); #endif // !AARCH64 - __ cas_long(addr, cmp.result(), val.result(), tmp1, tmp2, result); - } - else { + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), tmp1, tmp2, result); + } else { ShouldNotReachHere(); } + return result; } +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + bool is_oop = type == T_OBJECT || type == T_ARRAY; + LIR_Opr result = new_register(type); + value.load_item(); + assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp = (UseCompressedOops && is_oop) ? new_pointer_register() : LIR_OprFact::illegalOpr; + __ xchg(addr_ptr, data, dst, tmp); + return result; +} + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + value.load_item(); + assert(type == T_INT LP64_ONLY( || type == T_LONG), "unexpected type"); + LIR_Opr tmp = new_register(type); + __ xadd(addr, value.result(), result, tmp); + return result; +} void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { address runtime_func; @@ -1669,110 +1595,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, // TODO-AARCH64 implement with ldar instruction __ load(address, result, info, lir_patch_none); } - -void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, - BasicType type, bool is_volatile) { -#ifdef AARCH64 - __ load(new LIR_Address(src, offset, type), dst); -#else - assert(offset->is_single_cpu(), "must be"); - if (is_volatile && dst->is_double_cpu()) { - LIR_Opr tmp = new_pointer_register(); - __ add(src, offset, tmp); - __ volatile_load_mem_reg(new LIR_Address(tmp, (intx)0, type), dst, NULL); - } else if (type == T_FLOAT || type == T_DOUBLE) { - // fld doesn't have indexed addressing mode - LIR_Opr tmp = new_register(T_INT); - __ add(src, offset, tmp); - __ load(new LIR_Address(tmp, (intx)0, type), dst); - } else { - __ load(new LIR_Address(src, offset, type), dst); - } -#endif // AARCH64 -} - -void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, - BasicType type, bool is_volatile) { -#ifdef AARCH64 - LIR_Address* addr = new LIR_Address(src, offset, type); - if (type == T_ARRAY || type == T_OBJECT) { - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - __ move(data, addr); - assert(src->is_register(), "must be register"); - post_barrier(LIR_OprFact::address(addr), data); - } else { - __ move(data, addr); - } -#else - assert(offset->is_single_cpu(), "must be"); - if (is_volatile && data->is_double_cpu()) { - LIR_Opr tmp = new_register(T_INT); - __ add(src, offset, tmp); - __ volatile_store_mem_reg(data, new LIR_Address(tmp, (intx)0, type), NULL); - } else if (type == T_FLOAT || type == T_DOUBLE) { - // fst doesn't have indexed addressing mode - LIR_Opr tmp = new_register(T_INT); - __ add(src, offset, tmp); - __ move(data, new LIR_Address(tmp, (intx)0, type)); - } else { - LIR_Address* addr = new LIR_Address(src, offset, type); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); -#if INCLUDE_ALL_GCS - if (is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } -#endif // INCLUDE_ALL_GCS - __ move(data, addr); - if (is_obj) { - assert(src->is_register(), "must be register"); - post_barrier(LIR_OprFact::address(addr), data); - } - } -#endif // AARCH64 -} - -void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { - BasicType type = x->basic_type(); - LIRItem src(x->object(), this); - LIRItem off(x->offset(), this); - LIRItem value(x->value(), this); - - src.load_item(); - if (x->is_add()) { - value.load_nonconstant(); - } else { - value.load_item(); - } - off.load_nonconstant(); - - LIR_Opr dst = rlock_result(x, type); - LIR_Opr data = value.result(); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - - assert (type == T_INT || type == T_LONG || (!x->is_add() && is_obj), "unexpected type"); - LIR_Opr addr_ptr = new_pointer_register(); - - __ add(src.result(), off.result(), addr_ptr); - - LIR_Address* addr = new LIR_Address(addr_ptr, (intx)0, type); - - if (x->is_add()) { - LIR_Opr tmp = new_register(type); - __ xadd(addr_ptr, data, dst, tmp); - } else { - LIR_Opr tmp = (UseCompressedOops && is_obj) ? new_pointer_register() : LIR_OprFact::illegalOpr; - if (is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - __ xchg(addr_ptr, data, dst, tmp); - if (is_obj) { - // Seems to be a precise address - post_barrier(LIR_OprFact::address(addr), data); - } - } -} diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index c91a9f7021e..885da76601d 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -42,11 +42,6 @@ #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "vmreg_arm.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#endif // Note: Rtemp usage is this file should not impact C2 and should be // correct as long as it is not implicitly used in lower layers (the @@ -356,6 +351,13 @@ static void restore_live_registers_without_return(StubAssembler* sasm, bool rest restore_live_registers(sasm, true, true, false, restore_fpu_registers); } +void StubAssembler::save_live_registers() { + save_live_registers(this); +} + +void StubAssembler::restore_live_registers_without_return() { + restore_live_registers_without_return(this); +} void Runtime1::initialize_pd() { } @@ -533,201 +535,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#if INCLUDE_ALL_GCS - case g1_pre_barrier_slow_id: - { - // Input: - // - pre_val pushed on the stack - - __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ mov(R0, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0); - __ should_not_reach_here(); - break; - } - - // save at least the registers that need saving if the runtime is called -#ifdef AARCH64 - __ raw_push(R0, R1); - __ raw_push(R2, R3); - const int nb_saved_regs = 4; -#else // AARCH64 - const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR); - const int nb_saved_regs = 6; - assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs"); - __ push(saved_regs); -#endif // AARCH64 - - const Register r_pre_val_0 = R0; // must be R0, to be ready for the runtime call - const Register r_index_1 = R1; - const Register r_buffer_2 = R2; - - Address queue_active(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address queue_index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - Label done; - Label runtime; - - // Is marking still active? - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldrb(R1, queue_active); - __ cbz(R1, done); - - __ ldr(r_index_1, queue_index); - __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize)); - __ ldr(r_buffer_2, buffer); - - __ subs(r_index_1, r_index_1, wordSize); - __ b(runtime, lt); - - __ str(r_index_1, queue_index); - __ str(r_pre_val_0, Address(r_buffer_2, r_index_1)); - - __ bind(done); - -#ifdef AARCH64 - __ raw_pop(R2, R3); - __ raw_pop(R0, R1); -#else // AARCH64 - __ pop(saved_regs); -#endif // AARCH64 - - __ ret(); - - __ bind(runtime); - - save_live_registers(sasm); - - assert(r_pre_val_0 == c_rarg0, "pre_val should be in R0"); - __ mov(c_rarg1, Rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), c_rarg0, c_rarg1); - - restore_live_registers_without_return(sasm); - - __ b(done); - } - break; - case g1_post_barrier_slow_id: - { - // Input: - // - store_addr, pushed on the stack - - __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ mov(R0, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0); - __ should_not_reach_here(); - break; - } - - Label done; - Label recheck; - Label runtime; - - Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - AddressLiteral cardtable(ci_card_table_address_as
(), relocInfo::none); - - // save at least the registers that need saving if the runtime is called -#ifdef AARCH64 - __ raw_push(R0, R1); - __ raw_push(R2, R3); - const int nb_saved_regs = 4; -#else // AARCH64 - const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR); - const int nb_saved_regs = 6; - assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs"); - __ push(saved_regs); -#endif // AARCH64 - - const Register r_card_addr_0 = R0; // must be R0 for the slow case - const Register r_obj_0 = R0; - const Register r_card_base_1 = R1; - const Register r_tmp2 = R2; - const Register r_index_2 = R2; - const Register r_buffer_3 = R3; - const Register tmp1 = Rtemp; - - __ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize)); - // Note: there is a comment in x86 code about not using - // ExternalAddress / lea, due to relocation not working - // properly for that address. Should be OK for arm, where we - // explicitly specify that 'cardtable' has a relocInfo::none - // type. - __ lea(r_card_base_1, cardtable); - __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift)); - - // first quick check without barrier - __ ldrb(r_tmp2, Address(r_card_addr_0)); - - __ cmp(r_tmp2, (int)G1CardTable::g1_young_card_val()); - __ b(recheck, ne); - - __ bind(done); - -#ifdef AARCH64 - __ raw_pop(R2, R3); - __ raw_pop(R0, R1); -#else // AARCH64 - __ pop(saved_regs); -#endif // AARCH64 - - __ ret(); - - __ bind(recheck); - - __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1); - - // reload card state after the barrier that ensures the stored oop was visible - __ ldrb(r_tmp2, Address(r_card_addr_0)); - - assert(CardTable::dirty_card_val() == 0, "adjust this code"); - __ cbz(r_tmp2, done); - - // storing region crossing non-NULL, card is clean. - // dirty card and log. - - assert(0 == (int)CardTable::dirty_card_val(), "adjust this code"); - if ((ci_card_table_address_as() & 0xff) == 0) { - // Card table is aligned so the lowest byte of the table address base is zero. - __ strb(r_card_base_1, Address(r_card_addr_0)); - } else { - __ strb(__ zero_register(r_tmp2), Address(r_card_addr_0)); - } - - __ ldr(r_index_2, queue_index); - __ ldr(r_buffer_3, buffer); - - __ subs(r_index_2, r_index_2, wordSize); - __ b(runtime, lt); // go to runtime if now negative - - __ str(r_index_2, queue_index); - - __ str(r_card_addr_0, Address(r_buffer_3, r_index_2)); - - __ b(done); - - __ bind(runtime); - - save_live_registers(sasm); - - assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0"); - __ mov(c_rarg1, Rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), c_rarg0, c_rarg1); - - restore_live_registers_without_return(sasm); - - __ b(done); - } - break; -#endif // INCLUDE_ALL_GCS case new_instance_id: case fast_new_instance_id: case fast_new_instance_init_check_id: diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 70081298d7d..b351deb1843 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -32,6 +32,11 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/thread.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif #define __ masm-> @@ -120,3 +125,243 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas #endif // !R9_IS_SCRATCHED #endif // !AARCH64 } + +#ifdef COMPILER1 + +#undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(*stub->entry()); + assert(stub->pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); + } + + __ cbz(pre_val_reg, *stub->continuation()); + ce->verify_reserved_argument_area_size(1); + __ str(pre_val_reg, Address(SP)); + __ call(bs->pre_barrier_c1_runtime_code_blob()->code_begin(), relocInfo::runtime_call_type); + + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + assert(stub->addr()->is_register(), "Precondition."); + assert(stub->new_val()->is_register(), "Precondition."); + Register new_val_reg = stub->new_val()->as_register(); + __ cbz(new_val_reg, *stub->continuation()); + ce->verify_reserved_argument_area_size(1); + __ str(stub->addr()->as_pointer_register(), Address(SP)); + __ call(bs->post_barrier_c1_runtime_code_blob()->code_begin(), relocInfo::runtime_call_type); + __ b(*stub->continuation()); +} + +#undef __ +#define __ sasm-> + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + // Input: + // - pre_val pushed on the stack + + __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); + + BarrierSet* bs = BarrierSet::barrier_set(); + if (bs->kind() != BarrierSet::G1BarrierSet) { + __ mov(R0, (int)id); + __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0); + __ should_not_reach_here(); + break; + } + + // save at least the registers that need saving if the runtime is called +#ifdef AARCH64 + __ raw_push(R0, R1); + __ raw_push(R2, R3); + const int nb_saved_regs = 4; +#else // AARCH64 + const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR); + const int nb_saved_regs = 6; + assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs"); + __ push(saved_regs); +#endif // AARCH64 + + const Register r_pre_val_0 = R0; // must be R0, to be ready for the runtime call + const Register r_index_1 = R1; + const Register r_buffer_2 = R2; + + Address queue_active(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + Address queue_index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + Label done; + Label runtime; + + // Is marking still active? + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(R1, queue_active); + __ cbz(R1, done); + + __ ldr(r_index_1, queue_index); + __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize)); + __ ldr(r_buffer_2, buffer); + + __ subs(r_index_1, r_index_1, wordSize); + __ b(runtime, lt); + + __ str(r_index_1, queue_index); + __ str(r_pre_val_0, Address(r_buffer_2, r_index_1)); + + __ bind(done); + +#ifdef AARCH64 + __ raw_pop(R2, R3); + __ raw_pop(R0, R1); +#else // AARCH64 + __ pop(saved_regs); +#endif // AARCH64 + + __ ret(); + + __ bind(runtime); + + __ save_live_registers(); + + assert(r_pre_val_0 == c_rarg0, "pre_val should be in R0"); + __ mov(c_rarg1, Rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), c_rarg0, c_rarg1); + + __ restore_live_registers_without_return(); + + __ b(done); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + // Input: + // - store_addr, pushed on the stack + + __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); + + BarrierSet* bs = BarrierSet::barrier_set(); + if (bs->kind() != BarrierSet::G1BarrierSet) { + __ mov(R0, (int)id); + __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0); + __ should_not_reach_here(); + break; + } + + Label done; + Label recheck; + Label runtime; + + Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); + Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); + + AddressLiteral cardtable(ci_card_table_address_as
(), relocInfo::none); + + // save at least the registers that need saving if the runtime is called +#ifdef AARCH64 + __ raw_push(R0, R1); + __ raw_push(R2, R3); + const int nb_saved_regs = 4; +#else // AARCH64 + const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR); + const int nb_saved_regs = 6; + assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs"); + __ push(saved_regs); +#endif // AARCH64 + + const Register r_card_addr_0 = R0; // must be R0 for the slow case + const Register r_obj_0 = R0; + const Register r_card_base_1 = R1; + const Register r_tmp2 = R2; + const Register r_index_2 = R2; + const Register r_buffer_3 = R3; + const Register tmp1 = Rtemp; + + __ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize)); + // Note: there is a comment in x86 code about not using + // ExternalAddress / lea, due to relocation not working + // properly for that address. Should be OK for arm, where we + // explicitly specify that 'cardtable' has a relocInfo::none + // type. + __ lea(r_card_base_1, cardtable); + __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift)); + + // first quick check without barrier + __ ldrb(r_tmp2, Address(r_card_addr_0)); + + __ cmp(r_tmp2, (int)G1CardTable::g1_young_card_val()); + __ b(recheck, ne); + + __ bind(done); + +#ifdef AARCH64 + __ raw_pop(R2, R3); + __ raw_pop(R0, R1); +#else // AARCH64 + __ pop(saved_regs); +#endif // AARCH64 + + __ ret(); + + __ bind(recheck); + + __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1); + + // reload card state after the barrier that ensures the stored oop was visible + __ ldrb(r_tmp2, Address(r_card_addr_0)); + + assert(CardTable::dirty_card_val() == 0, "adjust this code"); + __ cbz(r_tmp2, done); + + // storing region crossing non-NULL, card is clean. + // dirty card and log. + + assert(0 == (int)CardTable::dirty_card_val(), "adjust this code"); + if ((ci_card_table_address_as() & 0xff) == 0) { + // Card table is aligned so the lowest byte of the table address base is zero. + __ strb(r_card_base_1, Address(r_card_addr_0)); + } else { + __ strb(__ zero_register(r_tmp2), Address(r_card_addr_0)); + } + + __ ldr(r_index_2, queue_index); + __ ldr(r_buffer_3, buffer); + + __ subs(r_index_2, r_index_2, wordSize); + __ b(runtime, lt); // go to runtime if now negative + + __ str(r_index_2, queue_index); + + __ str(r_card_addr_0, Address(r_buffer_3, r_index_2)); + + __ b(done); + + __ bind(runtime); + + __ save_live_registers(); + + assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0"); + __ mov(c_rarg1, Rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), c_rarg0, c_rarg1); + + __ restore_live_registers_without_return(); + + __ b(done); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp index 17627298c4b..babc24cc8ec 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp @@ -27,6 +27,12 @@ #include "asm/macroAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "utilities/macros.hpp" + +class LIR_Assembler; +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -34,6 +40,14 @@ protected: Register addr, Register count, int callee_saved_regs); void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp); + +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); +#endif }; #endif // CPU_ARM_GC_G1_G1BARRIERSETASSEMBLER_ARM_HPP diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index 6ba9b9b8ce9..cb6452c6f70 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -33,9 +33,6 @@ #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" #include "vmreg_ppc.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -470,58 +467,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ b(_continuation); } - -/////////////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that marking is in progress. - // If do_load() is true then we have to emit the - // load of the previous value; otherwise it has already - // been loaded into _pre_val. - - __ bind(_entry); - - assert(pre_val()->is_register(), "Precondition."); - Register pre_val_reg = pre_val()->as_register(); - - if (do_load()) { - ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); - } - - __ cmpdi(CCR0, pre_val_reg, 0); - __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation); - - address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id); - //__ load_const_optimized(R0, stub); - __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); - __ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack. - __ mtctr(R0); - __ bctrl(); - __ b(_continuation); -} - -void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - - assert(addr()->is_register(), "Precondition."); - assert(new_val()->is_register(), "Precondition."); - Register addr_reg = addr()->as_pointer_register(); - Register new_val_reg = new_val()->as_register(); - - __ cmpdi(CCR0, new_val_reg, 0); - __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation); - - address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id); - //__ load_const_optimized(R0, stub); - __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); - __ mtctr(R0); - __ mr(R0, addr_reg); // Pass addr in R0. - __ bctrl(); - __ b(_continuation); -} - -#endif // INCLUDE_ALL_GCS -/////////////////////////////////////////////////////////////////////////////////// - #undef __ diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index f79db307067..422c2aa3005 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2978,7 +2978,9 @@ void LIR_Assembler::peephole(LIR_List* lir) { void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) { - const Register Rptr = src->as_pointer_register(), + const LIR_Address *addr = src->as_address_ptr(); + assert(addr->disp() == 0 && addr->index()->is_illegal(), "use leal!"); + const Register Rptr = addr->base()->as_pointer_register(), Rtmp = tmp->as_register(); Register Rco = noreg; if (UseCompressedOops && data->is_oop()) { diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index 20b2801a2a2..4fadd0c9961 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -149,7 +149,12 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, // Accumulate fixed displacements. if (index->is_constant()) { - large_disp += (intx)(index->as_constant_ptr()->as_jint()) << shift; + LIR_Const *constant = index->as_constant_ptr(); + if (constant->type() == T_LONG) { + large_disp += constant->as_jlong() << shift; + } else { + large_disp += (intx)(constant->as_jint()) << shift; + } index = LIR_OprFact::illegalOpr; } @@ -190,7 +195,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type, bool needs_card_mark) { + BasicType type) { int elem_size = type2aelembytes(type); int shift = exact_log2(elem_size); @@ -230,13 +235,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o __ add(index_opr, array_opr, base_opr); } } - if (needs_card_mark) { - LIR_Opr ptr = new_pointer_register(); - __ add(base_opr, LIR_OprFact::intptrConst(offset), ptr); - return new LIR_Address(ptr, type); - } else { - return new LIR_Address(base_opr, offset, type); - } + return new LIR_Address(base_opr, offset, type); } @@ -320,80 +319,12 @@ void LIRGenerator::store_stack_parameter(LIR_Opr item, ByteSize offset_from_sp) // visitor functions //---------------------------------------------------------------------- -void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { - assert(x->is_pinned(),""); - bool needs_range_check = x->compute_needs_range_check(); - bool use_length = x->length() != NULL; - bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || - !get_jobject_constant(x->value())->is_null_object() || - x->should_profile()); - - LIRItem array(x->array(), this); - LIRItem index(x->index(), this); - LIRItem value(x->value(), this); - LIRItem length(this); - - array.load_item(); - index.load_nonconstant(); - - if (use_length && needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } - if (needs_store_check || x->check_boolean()) { - value.load_item(); - } else { - value.load_for_store(x->elt_type()); - } - - set_no_result(x); - - // The CodeEmitInfo must be duplicated for each different - // LIR-instruction because spilling can occur anywhere between two - // instructions and so the debug information must be different. - CodeEmitInfo* range_check_info = state_for(x); - CodeEmitInfo* null_check_info = NULL; - if (x->needs_null_check()) { - null_check_info = new CodeEmitInfo(range_check_info); - } - - // Emit array address setup early so it schedules better. - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); - - if (GenerateRangeChecks && needs_range_check) { - if (use_length) { - __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); - } else { - array_range_check(array.result(), index.result(), null_check_info, range_check_info); - // Range_check also does the null check. - null_check_info = NULL; - } - } - - if (GenerateArrayStoreCheck && needs_store_check) { - // Following registers are used by slow_subtype_check: - LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass - LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass - LIR_Opr tmp3 = FrameMap::R6_opr; // temp - - CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); - __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, - store_check_info, x->profiled_method(), x->profiled_bci()); - } - - if (obj_store) { - // Needs GC write barriers. - pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); - __ move(result, array_addr, null_check_info); - if (obj_store) { - // Precise card mark. - post_barrier(LIR_OprFact::address(array_addr), value.result()); - } +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_opr; // temp + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); } @@ -702,24 +633,68 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { } -void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { - assert(x->number_of_arguments() == 4, "wrong type"); - LIRItem obj (x->argument_at(0), this); // object - LIRItem offset(x->argument_at(1), this); // offset of field - LIRItem cmp (x->argument_at(2), this); // Value to compare with field. - LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp. - +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { + LIR_Opr result = new_register(T_INT); LIR_Opr t1 = LIR_OprFact::illegalOpr; LIR_Opr t2 = LIR_OprFact::illegalOpr; - LIR_Opr addr = new_pointer_register(); + cmp_value.load_item(); + new_value.load_item(); - // Get address of field. - obj.load_item(); - offset.load_item(); - cmp.load_item(); - val.load_item(); + // Volatile load may be followed by Unsafe CAS. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } else { + __ membar_release(); + } - __ add(obj.result(), offset.result(), addr); + if (type == T_OBJECT || type == T_ARRAY) { + if (UseCompressedOops) { + t1 = new_register(T_OBJECT); + t2 = new_register(T_OBJECT); + } + __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else if (type == T_INT) { + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else if (type == T_LONG) { + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else { + Unimplemented(); + } + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, type); + return result; +} + + +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + LIR_Opr tmp = FrameMap::R0_opr; + + value.load_item(); + + // Volatile load may be followed by Unsafe CAS. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } else { + __ membar_release(); + } + + __ xchg(addr, value.result(), result, tmp); + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar_acquire(); + } else { + __ membar(); + } + return result; +} + + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + LIR_Opr tmp = FrameMap::R0_opr; + + value.load_item(); // Volatile load may be followed by Unsafe CAS. if (support_IRIW_for_not_multiple_copy_atomic_cpu) { @@ -728,33 +703,14 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { __ membar_release(); } - if (type == objectType) { // Write-barrier needed for Object fields. - // Only cmp value can get overwritten, no do_load required. - pre_barrier(LIR_OprFact::illegalOpr /* addr */, cmp.result() /* pre_val */, - false /* do_load */, false /* patch */, NULL); - } + __ xadd(addr, value.result(), result, tmp); - if (type == objectType) { - if (UseCompressedOops) { - t1 = new_register(T_OBJECT); - t2 = new_register(T_OBJECT); - } - __ cas_obj(addr, cmp.result(), val.result(), t1, t2); - } else if (type == intType) { - __ cas_int(addr, cmp.result(), val.result(), t1, t2); - } else if (type == longType) { - __ cas_long(addr, cmp.result(), val.result(), t1, t2); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar_acquire(); } else { - ShouldNotReachHere(); - } - // Benerate conditional move of boolean result. - LIR_Opr result = rlock_result(x); - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), - result, as_BasicType(type)); - if (type == objectType) { // Write-barrier needed for Object fields. - // Precise card mark since could either be object or array. - post_barrier(addr, val.result()); + __ membar(); } + return result; } @@ -1255,110 +1211,6 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, } -void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, - BasicType type, bool is_volatile) { - LIR_Opr base_op = src; - LIR_Opr index_op = offset; - - bool is_obj = (type == T_ARRAY || type == T_OBJECT); -#ifndef _LP64 - if (is_volatile && type == T_LONG) { - __ volatile_store_unsafe_reg(data, src, offset, type, NULL, lir_patch_none); - } else -#endif - { - if (type == T_BOOLEAN) { - type = T_BYTE; - } - LIR_Address* addr; - if (type == T_ARRAY || type == T_OBJECT) { - LIR_Opr tmp = new_pointer_register(); - __ add(base_op, index_op, tmp); - addr = new LIR_Address(tmp, type); - } else { - addr = new LIR_Address(base_op, index_op, type); - } - - if (is_obj) { - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - // _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr)); - } - __ move(data, addr); - if (is_obj) { - // This address is precise. - post_barrier(LIR_OprFact::address(addr), data); - } - } -} - - -void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, - BasicType type, bool is_volatile) { -#ifndef _LP64 - if (is_volatile && type == T_LONG) { - __ volatile_load_unsafe_reg(src, offset, dst, type, NULL, lir_patch_none); - } else -#endif - { - LIR_Address* addr = new LIR_Address(src, offset, type); - __ load(addr, dst); - } -} - - -void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { - BasicType type = x->basic_type(); - LIRItem src(x->object(), this); - LIRItem off(x->offset(), this); - LIRItem value(x->value(), this); - - src.load_item(); - value.load_item(); - off.load_nonconstant(); - - LIR_Opr dst = rlock_result(x, type); - LIR_Opr data = value.result(); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - - LIR_Opr tmp = FrameMap::R0_opr; - LIR_Opr ptr = new_pointer_register(); - __ add(src.result(), off.result(), ptr); - - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar(); - } else { - __ membar_release(); - } - - if (x->is_add()) { - __ xadd(ptr, data, dst, tmp); - } else { - const bool can_move_barrier = true; // TODO: port GraphKit::can_move_pre_barrier() from C2 - if (!can_move_barrier && is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - __ xchg(ptr, data, dst, tmp); - if (is_obj) { - // Seems to be a precise address. - post_barrier(ptr, data); - if (can_move_barrier) { - pre_barrier(LIR_OprFact::illegalOpr, dst /* pre_val */, - false /* do_load */, false /* patch */, NULL); - } - } - } - - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ membar_acquire(); - } else { - __ membar(); - } -} - - void LIRGenerator::do_update_CRC32(Intrinsic* x) { assert(UseCRC32Intrinsics, "or should not be here"); LIR_Opr result = rlock_result(x); diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 032251ddaba..196bb47d3f8 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -42,11 +42,6 @@ #include "utilities/align.hpp" #include "utilities/macros.hpp" #include "vmreg_ppc.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#endif // Implementation of StubAssembler @@ -708,164 +703,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#if INCLUDE_ALL_GCS - case g1_pre_barrier_slow_id: - { - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - goto unimplemented_entry; - } - - __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); - - // Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2. - const int stack_slots = 3; - Register pre_val = R0; // previous value of memory - Register tmp = R14; - Register tmp2 = R15; - - Label refill, restart, marking_not_active; - int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - // Spill - __ std(tmp, -16, R1_SP); - __ std(tmp2, -24, R1_SP); - - // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(tmp, satb_q_active_byte_offset, R16_thread); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(tmp, satb_q_active_byte_offset, R16_thread); - } - __ cmpdi(CCR0, tmp, 0); - __ beq(CCR0, marking_not_active); - - __ bind(restart); - // Load the index into the SATB buffer. SATBMarkQueue::_index is a - // size_t so ld_ptr is appropriate. - __ ld(tmp, satb_q_index_byte_offset, R16_thread); - - // index == 0? - __ cmpdi(CCR0, tmp, 0); - __ beq(CCR0, refill); - - __ ld(tmp2, satb_q_buf_byte_offset, R16_thread); - __ ld(pre_val, -8, R1_SP); // Load from stack. - __ addi(tmp, tmp, -oopSize); - - __ std(tmp, satb_q_index_byte_offset, R16_thread); - __ stdx(pre_val, tmp2, tmp); // [_buf + index] := - - __ bind(marking_not_active); - // Restore temp registers and return-from-leaf. - __ ld(tmp2, -24, R1_SP); - __ ld(tmp, -16, R1_SP); - __ blr(); - - __ bind(refill); - const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; - __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 - __ mflr(R0); - __ std(R0, _abi(lr), R1_SP); - __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread); - __ pop_frame(); - __ ld(R0, _abi(lr), R1_SP); - __ mtlr(R0); - __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 - __ b(restart); - } - break; - - case g1_post_barrier_slow_id: - { - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - goto unimplemented_entry; - } - - __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); - - // Using stack slots: spill addr, spill tmp2 - const int stack_slots = 2; - Register tmp = R0; - Register addr = R14; - Register tmp2 = R15; - jbyte* byte_map_base = ci_card_table_address(); - - Label restart, refill, ret; - - // Spill - __ std(addr, -8, R1_SP); - __ std(tmp2, -16, R1_SP); - - __ srdi(addr, R0, CardTable::card_shift); // Addr is passed in R0. - __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp); - __ add(addr, tmp2, addr); - __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] - - // Return if young card. - __ cmpwi(CCR0, tmp, G1CardTable::g1_young_card_val()); - __ beq(CCR0, ret); - - // Return if sequential consistent value is already dirty. - __ membar(Assembler::StoreLoad); - __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] - - __ cmpwi(CCR0, tmp, G1CardTable::dirty_card_val()); - __ beq(CCR0, ret); - - // Not dirty. - - // First, dirty it. - __ li(tmp, G1CardTable::dirty_card_val()); - __ stb(tmp, 0, addr); - - int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - - __ bind(restart); - - // Get the index into the update buffer. DirtyCardQueue::_index is - // a size_t so ld_ptr is appropriate here. - __ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread); - - // index == 0? - __ cmpdi(CCR0, tmp2, 0); - __ beq(CCR0, refill); - - __ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread); - __ addi(tmp2, tmp2, -oopSize); - - __ std(tmp2, dirty_card_q_index_byte_offset, R16_thread); - __ add(tmp2, tmp, tmp2); - __ std(addr, 0, tmp2); // [_buf + index] := - - // Restore temp registers and return-from-leaf. - __ bind(ret); - __ ld(tmp2, -16, R1_SP); - __ ld(addr, -8, R1_SP); - __ blr(); - - __ bind(refill); - const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; - __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 - __ mflr(R0); - __ std(R0, _abi(lr), R1_SP); - __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call - __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread); - __ pop_frame(); - __ ld(R0, _abi(lr), R1_SP); - __ mtlr(R0); - __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 - __ b(restart); - } - break; -#endif // INCLUDE_ALL_GCS - case predicate_failed_trap_id: { __ set_info("predicate_failed_trap", dont_gc_arguments); @@ -889,7 +726,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { break; default: - unimplemented_entry: { __ set_info("unimplemented entry", dont_gc_arguments); __ mflr(R0); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp index 9c05814b5de..23e86eea0f2 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp @@ -26,12 +26,17 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" +#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/heapRegion.hpp" #include "interpreter/interp_masm.hpp" #include "runtime/sharedRuntime.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif #define __ masm-> @@ -339,4 +344,209 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value __ bind(done); } +#ifdef COMPILER1 + #undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(*stub->entry()); + + assert(stub->pre_val()->is_register(), "Precondition."); + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); + } + + __ cmpdi(CCR0, pre_val_reg, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + address c_code = bs->pre_barrier_c1_runtime_code_blob()->code_begin(); + //__ load_const_optimized(R0, c_code); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(c_code)); + __ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack. + __ mtctr(R0); + __ bctrl(); + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + + assert(stub->addr()->is_register(), "Precondition."); + assert(stub->new_val()->is_register(), "Precondition."); + Register addr_reg = stub->addr()->as_pointer_register(); + Register new_val_reg = stub->new_val()->as_register(); + + __ cmpdi(CCR0, new_val_reg, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + address c_code = bs->post_barrier_c1_runtime_code_blob()->code_begin(); + //__ load_const_optimized(R0, c_code); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(c_code)); + __ mtctr(R0); + __ mr(R0, addr_reg); // Pass addr in R0. + __ bctrl(); + __ b(*stub->continuation()); +} + +#undef __ +#define __ sasm-> + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + BarrierSet* bs = BarrierSet::barrier_set(); + + __ set_info("g1_pre_barrier_slow_id", false); + + // Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2. + const int stack_slots = 3; + Register pre_val = R0; // previous value of memory + Register tmp = R14; + Register tmp2 = R15; + + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); + int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); + int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); + + // Spill + __ std(tmp, -16, R1_SP); + __ std(tmp2, -24, R1_SP); + + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwz(tmp, satb_q_active_byte_offset, R16_thread); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(tmp, satb_q_active_byte_offset, R16_thread); + } + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, marking_not_active); + + __ bind(restart); + // Load the index into the SATB buffer. SATBMarkQueue::_index is a + // size_t so ld_ptr is appropriate. + __ ld(tmp, satb_q_index_byte_offset, R16_thread); + + // index == 0? + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, refill); + + __ ld(tmp2, satb_q_buf_byte_offset, R16_thread); + __ ld(pre_val, -8, R1_SP); // Load from stack. + __ addi(tmp, tmp, -oopSize); + + __ std(tmp, satb_q_index_byte_offset, R16_thread); + __ stdx(pre_val, tmp2, tmp); // [_buf + index] := + + __ bind(marking_not_active); + // Restore temp registers and return-from-leaf. + __ ld(tmp2, -24, R1_SP); + __ ld(tmp, -16, R1_SP); + __ blr(); + + __ bind(refill); + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread); + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ b(restart); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); + + __ set_info("g1_post_barrier_slow_id", false); + + // Using stack slots: spill addr, spill tmp2 + const int stack_slots = 2; + Register tmp = R0; + Register addr = R14; + Register tmp2 = R15; + jbyte* byte_map_base = bs->card_table()->byte_map_base(); + + Label restart, refill, ret; + + // Spill + __ std(addr, -8, R1_SP); + __ std(tmp2, -16, R1_SP); + + __ srdi(addr, R0, CardTable::card_shift); // Addr is passed in R0. + __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp); + __ add(addr, tmp2, addr); + __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] + + // Return if young card. + __ cmpwi(CCR0, tmp, G1CardTable::g1_young_card_val()); + __ beq(CCR0, ret); + + // Return if sequential consistent value is already dirty. + __ membar(Assembler::StoreLoad); + __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] + + __ cmpwi(CCR0, tmp, G1CardTable::dirty_card_val()); + __ beq(CCR0, ret); + + // Not dirty. + + // First, dirty it. + __ li(tmp, G1CardTable::dirty_card_val()); + __ stb(tmp, 0, addr); + + int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); + int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); + + __ bind(restart); + + // Get the index into the update buffer. DirtyCardQueue::_index is + // a size_t so ld_ptr is appropriate here. + __ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread); + + // index == 0? + __ cmpdi(CCR0, tmp2, 0); + __ beq(CCR0, refill); + + __ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread); + __ addi(tmp2, tmp2, -oopSize); + + __ std(tmp2, dirty_card_q_index_byte_offset, R16_thread); + __ add(tmp2, tmp, tmp2); + __ std(addr, 0, tmp2); // [_buf + index] := + + // Restore temp registers and return-from-leaf. + __ bind(ret); + __ ld(tmp2, -16, R1_SP); + __ ld(addr, -8, R1_SP); + __ blr(); + + __ bind(refill); + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call + __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread); + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ b(restart); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp index 71ac08e1d83..d6c6a7e2286 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp @@ -28,6 +28,12 @@ #include "asm/macroAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "utilities/macros.hpp" + +class LIR_Assembler; +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -45,6 +51,14 @@ protected: Register tmp1, Register tmp2, Register tmp3, bool needs_frame); public: +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); +#endif + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register base, RegisterOrConstant ind_or_offs, Register dst, Register tmp1, Register tmp2, bool needs_frame, Label *is_null = NULL); diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp index 4b0bf2bb11b..212b6d91d25 100644 --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -34,9 +34,6 @@ #include "utilities/align.hpp" #include "utilities/macros.hpp" #include "vmreg_s390.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> #undef CHECK_BAILOUT @@ -453,46 +450,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ branch_optimized(Assembler::bcondAlways, _continuation); } - -/////////////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that marking is in progress. - // If do_load() is true then we have to emit the - // load of the previous value; otherwise it has already - // been loaded into _pre_val. - __ bind(_entry); - ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots. - assert(pre_val()->is_register(), "Precondition."); - - Register pre_val_reg = pre_val()->as_register(); - - if (do_load()) { - ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); - } - - __ z_ltgr(Z_R1_scratch, pre_val_reg); // Pass oop in Z_R1_scratch to Runtime1::g1_pre_barrier_slow_id. - __ branch_optimized(Assembler::bcondZero, _continuation); - ce->emit_call_c(Runtime1::entry_for (Runtime1::g1_pre_barrier_slow_id)); - CHECK_BAILOUT(); - __ branch_optimized(Assembler::bcondAlways, _continuation); -} - -void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots. - assert(addr()->is_register(), "Precondition."); - assert(new_val()->is_register(), "Precondition."); - Register new_val_reg = new_val()->as_register(); - __ z_ltgr(new_val_reg, new_val_reg); - __ branch_optimized(Assembler::bcondZero, _continuation); - __ z_lgr(Z_R1_scratch, addr()->as_pointer_register()); - ce->emit_call_c(Runtime1::entry_for (Runtime1::g1_post_barrier_slow_id)); - CHECK_BAILOUT(); - __ branch_optimized(Assembler::bcondAlways, _continuation); -} - -#endif // INCLUDE_ALL_GCS - #undef __ diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 1478a03ee11..62bb5a4f0db 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -572,80 +572,143 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { assert(src->is_constant(), "should not call otherwise"); assert(dest->is_address(), "should not call otherwise"); - // See special case in LIRGenerator::do_StoreIndexed. - // T_BYTE: Special case for card mark store. - assert(type == T_BYTE || !dest->as_address_ptr()->index()->is_valid(), "not supported"); + LIR_Const* c = src->as_constant_ptr(); Address addr = as_Address(dest->as_address_ptr()); int store_offset = -1; - unsigned int lmem = 0; - unsigned int lcon = 0; - int64_t cbits = 0; - switch (type) { - case T_INT: // fall through - case T_FLOAT: - lmem = 4; lcon = 4; cbits = c->as_jint_bits(); - break; - case T_ADDRESS: - lmem = 8; lcon = 4; cbits = c->as_jint_bits(); - break; - - case T_OBJECT: // fall through - case T_ARRAY: - if (c->as_jobject() == NULL) { - if (UseCompressedOops && !wide) { - store_offset = __ store_const(addr, (int32_t)NULL_WORD, 4, 4); + if (dest->as_address_ptr()->index()->is_valid()) { + switch (type) { + case T_INT: // fall through + case T_FLOAT: + __ load_const_optimized(Z_R0_scratch, c->as_jint_bits()); + store_offset = __ offset(); + if (Immediate::is_uimm12(addr.disp())) { + __ z_st(Z_R0_scratch, addr); } else { - store_offset = __ store_const(addr, (int64_t)NULL_WORD, 8, 8); + __ z_sty(Z_R0_scratch, addr); } - } else { - jobject2reg(c->as_jobject(), Z_R1_scratch); - if (UseCompressedOops && !wide) { - __ encode_heap_oop(Z_R1_scratch); - store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false); + break; + + case T_ADDRESS: + __ load_const_optimized(Z_R1_scratch, c->as_jint_bits()); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + break; + + case T_OBJECT: // fall through + case T_ARRAY: + if (c->as_jobject() == NULL) { + if (UseCompressedOops && !wide) { + __ clear_reg(Z_R1_scratch, false); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false); + } else { + __ clear_reg(Z_R1_scratch, true); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + } } else { - store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + jobject2reg(c->as_jobject(), Z_R1_scratch); + if (UseCompressedOops && !wide) { + __ encode_heap_oop(Z_R1_scratch); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false); + } else { + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + } } - } - assert(store_offset >= 0, "check"); - break; + assert(store_offset >= 0, "check"); + break; - case T_LONG: // fall through - case T_DOUBLE: - lmem = 8; lcon = 8; cbits = (int64_t)(c->as_jlong_bits()); - break; + case T_LONG: // fall through + case T_DOUBLE: + __ load_const_optimized(Z_R1_scratch, (int64_t)(c->as_jlong_bits())); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + break; - case T_BOOLEAN: // fall through - case T_BYTE: - lmem = 1; lcon = 1; cbits = (int8_t)(c->as_jint()); - break; + case T_BOOLEAN: // fall through + case T_BYTE: + __ load_const_optimized(Z_R0_scratch, (int8_t)(c->as_jint())); + store_offset = __ offset(); + if (Immediate::is_uimm12(addr.disp())) { + __ z_stc(Z_R0_scratch, addr); + } else { + __ z_stcy(Z_R0_scratch, addr); + } + break; - case T_CHAR: // fall through - case T_SHORT: - lmem = 2; lcon = 2; cbits = (int16_t)(c->as_jint()); - break; + case T_CHAR: // fall through + case T_SHORT: + __ load_const_optimized(Z_R0_scratch, (int16_t)(c->as_jint())); + store_offset = __ offset(); + if (Immediate::is_uimm12(addr.disp())) { + __ z_sth(Z_R0_scratch, addr); + } else { + __ z_sthy(Z_R0_scratch, addr); + } + break; - default: - ShouldNotReachHere(); - }; - - // Index register is normally not supported, but for - // LIRGenerator::CardTableBarrierSet_post_barrier we make an exception. - if (type == T_BYTE && dest->as_address_ptr()->index()->is_valid()) { - __ load_const_optimized(Z_R0_scratch, (int8_t)(c->as_jint())); - store_offset = __ offset(); - if (Immediate::is_uimm12(addr.disp())) { - __ z_stc(Z_R0_scratch, addr); - } else { - __ z_stcy(Z_R0_scratch, addr); + default: + ShouldNotReachHere(); } - } - if (store_offset == -1) { - store_offset = __ store_const(addr, cbits, lmem, lcon); - assert(store_offset >= 0, "check"); + } else { // no index + + unsigned int lmem = 0; + unsigned int lcon = 0; + int64_t cbits = 0; + + switch (type) { + case T_INT: // fall through + case T_FLOAT: + lmem = 4; lcon = 4; cbits = c->as_jint_bits(); + break; + + case T_ADDRESS: + lmem = 8; lcon = 4; cbits = c->as_jint_bits(); + break; + + case T_OBJECT: // fall through + case T_ARRAY: + if (c->as_jobject() == NULL) { + if (UseCompressedOops && !wide) { + store_offset = __ store_const(addr, (int32_t)NULL_WORD, 4, 4); + } else { + store_offset = __ store_const(addr, (int64_t)NULL_WORD, 8, 8); + } + } else { + jobject2reg(c->as_jobject(), Z_R1_scratch); + if (UseCompressedOops && !wide) { + __ encode_heap_oop(Z_R1_scratch); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false); + } else { + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + } + } + assert(store_offset >= 0, "check"); + break; + + case T_LONG: // fall through + case T_DOUBLE: + lmem = 8; lcon = 8; cbits = (int64_t)(c->as_jlong_bits()); + break; + + case T_BOOLEAN: // fall through + case T_BYTE: + lmem = 1; lcon = 1; cbits = (int8_t)(c->as_jint()); + break; + + case T_CHAR: // fall through + case T_SHORT: + lmem = 2; lcon = 2; cbits = (int16_t)(c->as_jint()); + break; + + default: + ShouldNotReachHere(); + } + + if (store_offset == -1) { + store_offset = __ store_const(addr, cbits, lmem, lcon); + assert(store_offset >= 0, "check"); + } } if (info != NULL) { diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index 7bb3190a101..fc5a2d6eac5 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -140,7 +140,13 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, int shift, int disp, BasicType type) { assert(base->is_register(), "must be"); if (index->is_constant()) { - intptr_t large_disp = ((intx)(index->as_constant_ptr()->as_jint()) << shift) + disp; + intx large_disp = disp; + LIR_Const *constant = index->as_constant_ptr(); + if (constant->type() == T_LONG) { + large_disp += constant->as_jlong() << shift; + } else { + large_disp += (intx)(constant->as_jint()) << shift; + } if (Displacement::is_validDisp(large_disp)) { return new LIR_Address(base, large_disp, type); } @@ -159,7 +165,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, } LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type, bool needs_card_mark) { + BasicType type) { int elem_size = type2aelembytes(type); int shift = exact_log2(elem_size); int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type); @@ -181,16 +187,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o index_opr, offset_in_bytes, type); } - if (needs_card_mark) { - // This store will need a precise card mark, so go ahead and - // compute the full adddres instead of computing once for the - // store and again for the card mark. - LIR_Opr tmp = new_pointer_register(); - __ leal(LIR_OprFact::address(addr), tmp); - return new LIR_Address(tmp, type); - } else { - return addr; - } + return addr; } LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { @@ -252,86 +249,11 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) // visitor functions //---------------------------------------------------------------------- -void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { - assert(x->is_pinned(),""); - bool needs_range_check = x->compute_needs_range_check(); - bool use_length = x->length() != NULL; - bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || - !get_jobject_constant(x->value())->is_null_object() || - x->should_profile()); - - LIRItem array(x->array(), this); - LIRItem index(x->index(), this); - LIRItem value(x->value(), this); - LIRItem length(this); - - array.load_item(); - index.load_nonconstant(20); - - if (use_length && needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } - if (needs_store_check || x->check_boolean()) { - value.load_item(); - } else { - value.load_for_store(x->elt_type()); - } - - set_no_result(x); - - // The CodeEmitInfo must be duplicated for each different - // LIR-instruction because spilling can occur anywhere between two - // instructions and so the debug information must be different. - CodeEmitInfo* range_check_info = state_for (x); - CodeEmitInfo* null_check_info = NULL; - if (x->needs_null_check()) { - null_check_info = new CodeEmitInfo(range_check_info); - } - - // Emit array address setup early so it schedules better. - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); - if (value.result()->is_constant() && array_addr->index()->is_valid()) { - // Constants cannot be stored with index register on ZARCH_64 (see LIR_Assembler::const2mem()). - LIR_Opr tmp = new_pointer_register(); - __ leal(LIR_OprFact::address(array_addr), tmp); - array_addr = new LIR_Address(tmp, x->elt_type()); - } - - if (GenerateRangeChecks && needs_range_check) { - if (use_length) { - __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); - } else { - array_range_check(array.result(), index.result(), null_check_info, range_check_info); - // Range_check also does the null check. - null_check_info = NULL; - } - } - - if (GenerateArrayStoreCheck && needs_store_check) { - LIR_Opr tmp1 = new_register(objectType); - LIR_Opr tmp2 = new_register(objectType); - LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - - CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); - __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci()); - } - - if (obj_store) { - // Needs GC write barriers. - pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - - LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); - __ move(result, array_addr, null_check_info); - - if (obj_store) { - // Precise card mark - post_barrier(LIR_OprFact::address(array_addr), value.result()); - } +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { + LIR_Opr tmp1 = new_register(objectType); + LIR_Opr tmp2 = new_register(objectType); + LIR_Opr tmp3 = LIR_OprFact::illegalOpr; + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); } void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { @@ -665,59 +587,42 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { } } -void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { - assert(x->number_of_arguments() == 4, "wrong type"); - LIRItem obj (x->argument_at(0), this); // object - LIRItem offset(x->argument_at(1), this); // offset of field - LIRItem cmp (x->argument_at(2), this); // Value to compare with field. - LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp. - - // Get address of field. - obj.load_item(); - offset.load_nonconstant(20); - cmp.load_item(); - val.load_item(); - - LIR_Opr addr = new_pointer_register(); - LIR_Address* a; - if (offset.result()->is_constant()) { - assert(Immediate::is_simm20(offset.result()->as_jlong()), "should have been loaded into register"); - a = new LIR_Address(obj.result(), - offset.result()->as_jlong(), - as_BasicType(type)); - } else { - a = new LIR_Address(obj.result(), - offset.result(), - 0, - as_BasicType(type)); - } - __ leal(LIR_OprFact::address(a), addr); - - if (type == objectType) { // Write-barrier needed for Object fields. - pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - - LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience - if (type == objectType) { - __ cas_obj(addr, cmp.result(), val.result(), new_register(T_OBJECT), new_register(T_OBJECT)); - } else if (type == intType) { - __ cas_int(addr, cmp.result(), val.result(), ill, ill); - } else if (type == longType) { - __ cas_long(addr, cmp.result(), val.result(), ill, ill); +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { + LIR_Opr t1 = LIR_OprFact::illegalOpr; + LIR_Opr t2 = LIR_OprFact::illegalOpr; + cmp_value.load_item(); + new_value.load_item(); + if (type == T_OBJECT) { + if (UseCompressedOops) { + t1 = new_register(T_OBJECT); + t2 = new_register(T_OBJECT); + } + __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else if (type == T_INT) { + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else if (type == T_LONG) { + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); } else { ShouldNotReachHere(); } // Generate conditional move of boolean result. - LIR_Opr result = rlock_result(x); + LIR_Opr result = new_register(T_INT); __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), - result, as_BasicType(type)); - if (type == objectType) { // Write-barrier needed for Object fields. - // Precise card mark since could either be object or array - post_barrier(addr, val.result()); - } + result, type); + return result; } +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + Unimplemented(); // Currently not supported on this platform. + return LIR_OprFact::illegalOpr; +} + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + value.load_item(); + __ xadd(addr, value.result(), result, LIR_OprFact::illegalOpr); + return result; +} void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { switch (x->id()) { @@ -1104,57 +1009,6 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, __ load(address, result, info); } - -void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, - BasicType type, bool is_volatile) { - LIR_Address* addr = new LIR_Address(src, offset, type); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - if (is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - __ move(data, addr); - assert(src->is_register(), "must be register"); - // Seems to be a precise address. - post_barrier(LIR_OprFact::address(addr), data); - } else { - __ move(data, addr); - } -} - - -void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, - BasicType type, bool is_volatile) { - LIR_Address* addr = new LIR_Address(src, offset, type); - __ load(addr, dst); -} - -void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { - BasicType type = x->basic_type(); - assert (x->is_add() && type != T_ARRAY && type != T_OBJECT, "not supported"); - LIRItem src(x->object(), this); - LIRItem off(x->offset(), this); - LIRItem value(x->value(), this); - - src.load_item(); - value.load_item(); - off.load_nonconstant(20); - - LIR_Opr dst = rlock_result(x, type); - LIR_Opr data = value.result(); - LIR_Opr offset = off.result(); - - LIR_Address* addr; - if (offset->is_constant()) { - assert(Immediate::is_simm20(offset->as_jlong()), "should have been loaded into register"); - addr = new LIR_Address(src.result(), offset->as_jlong(), type); - } else { - addr = new LIR_Address(src.result(), offset, type); - } - - __ xadd(LIR_OprFact::address(addr), data, dst, LIR_OprFact::illegalOpr); -} - void LIRGenerator::do_update_CRC32(Intrinsic* x) { assert(UseCRC32Intrinsics, "or should not be here"); LIR_Opr result = rlock_result(x); diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index fd14891baf9..b2c5cc1fa3e 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -42,11 +42,6 @@ #include "utilities/macros.hpp" #include "vmreg_s390.inline.hpp" #include "registerSaver_s390.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#endif // Implementation of StubAssembler @@ -190,15 +185,6 @@ static OopMap* save_live_registers_except_r2(StubAssembler* sasm, bool save_fpu_ return RegisterSaver::save_live_registers(sasm, reg_set); } -static OopMap* save_volatile_registers(StubAssembler* sasm, Register return_pc = Z_R14) { - __ block_comment("save_volatile_registers"); - RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers; - int frame_size_in_slots = - RegisterSaver::live_reg_frame_size(reg_set) / VMRegImpl::stack_slot_size; - sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word); - return RegisterSaver::save_live_registers(sasm, reg_set, return_pc); -} - static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { __ block_comment("restore_live_registers"); RegisterSaver::RegisterSet reg_set = @@ -214,12 +200,6 @@ static void restore_live_registers_except_r2(StubAssembler* sasm, bool restore_f RegisterSaver::restore_live_registers(sasm, RegisterSaver::all_registers_except_r2); } -static void restore_volatile_registers(StubAssembler* sasm) { - __ block_comment("restore_volatile_registers"); - RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers; - RegisterSaver::restore_live_registers(sasm, reg_set); -} - void Runtime1::initialize_pd() { // Nothing to do. } @@ -764,160 +744,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { break; #endif // TODO -#if INCLUDE_ALL_GCS - case g1_pre_barrier_slow_id: - { // Z_R1_scratch: previous value of memory - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ should_not_reach_here(FILE_AND_LINE); - break; - } - - __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); - - Register pre_val = Z_R1_scratch; - Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val. - Register tmp2 = Z_R7; - - Label refill, restart, marking_not_active; - int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - // Save tmp registers (see assertion in G1PreBarrierStub::emit_code()). - __ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - __ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - - // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset)); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset)); - } - __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently. - - __ bind(restart); - // Load the index into the SATB buffer. SATBMarkQueue::_index is a - // size_t so ld_ptr is appropriate. - __ z_ltg(tmp, satb_q_index_byte_offset, Z_R0, Z_thread); - - // index == 0? - __ z_brz(refill); - - __ z_lg(tmp2, satb_q_buf_byte_offset, Z_thread); - __ add2reg(tmp, -oopSize); - - __ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := - __ z_stg(tmp, satb_q_index_byte_offset, Z_thread); - - __ bind(marking_not_active); - // Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()). - __ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - __ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - __ z_br(Z_R14); - - __ bind(refill); - save_volatile_registers(sasm); - __ z_lgr(tmp, pre_val); // save pre_val - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), - Z_thread); - __ z_lgr(pre_val, tmp); // restore pre_val - restore_volatile_registers(sasm); - __ z_bru(restart); - } - break; - - case g1_post_barrier_slow_id: - { // Z_R1_scratch: oop address, address of updated memory slot - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ should_not_reach_here(FILE_AND_LINE); - break; - } - - __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); - - Register addr_oop = Z_R1_scratch; - Register addr_card = Z_R1_scratch; - Register r1 = Z_R6; // Must be saved/restored. - Register r2 = Z_R7; // Must be saved/restored. - Register cardtable = r1; // Must be non-volatile, because it is used to save addr_card. - jbyte* byte_map_base = ci_card_table_address(); - - // Save registers used below (see assertion in G1PreBarrierStub::emit_code()). - __ z_stg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - - Label not_already_dirty, restart, refill, young_card; - - // Calculate address of card corresponding to the updated oop slot. - AddressLiteral rs(byte_map_base); - __ z_srlg(addr_card, addr_oop, CardTable::card_shift); - addr_oop = noreg; // dead now - __ load_const_optimized(cardtable, rs); // cardtable := - __ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable - - __ z_cli(0, addr_card, (int)G1CardTable::g1_young_card_val()); - __ z_bre(young_card); - - __ z_sync(); // Required to support concurrent cleaning. - - __ z_cli(0, addr_card, (int)CardTable::dirty_card_val()); - __ z_brne(not_already_dirty); - - __ bind(young_card); - // We didn't take the branch, so we're already dirty: restore - // used registers and return. - __ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - __ z_br(Z_R14); - - // Not dirty. - __ bind(not_already_dirty); - - // First, dirty it: [addr_card] := 0 - __ z_mvi(0, addr_card, CardTable::dirty_card_val()); - - Register idx = cardtable; // Must be non-volatile, because it is used to save addr_card. - Register buf = r2; - cardtable = noreg; // now dead - - // Save registers used below (see assertion in G1PreBarrierStub::emit_code()). - __ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - - ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset(); - ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset(); - - __ bind(restart); - - // Get the index into the update buffer. DirtyCardQueue::_index is - // a size_t so z_ltg is appropriate here. - __ z_ltg(idx, Address(Z_thread, dirty_card_q_index_byte_offset)); - - // index == 0? - __ z_brz(refill); - - __ z_lg(buf, Address(Z_thread, dirty_card_q_buf_byte_offset)); - __ add2reg(idx, -oopSize); - - __ z_stg(addr_card, 0, idx, buf); // [_buf + index] := - __ z_stg(idx, Address(Z_thread, dirty_card_q_index_byte_offset)); - // Restore killed registers and return. - __ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - __ z_lg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); - __ z_br(Z_R14); - - __ bind(refill); - save_volatile_registers(sasm); - __ z_lgr(idx, addr_card); // Save addr_card, tmp3 must be non-volatile. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), - Z_thread); - __ z_lgr(addr_card, idx); - restore_volatile_registers(sasm); // Restore addr_card. - __ z_bru(restart); - } - break; -#endif // INCLUDE_ALL_GCS case predicate_failed_trap_id: { __ set_info("predicate_failed_trap", dont_gc_arguments); diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 0697fe8d68e..6a17d74a4a6 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -33,6 +33,11 @@ #include "gc/g1/heapRegion.hpp" #include "interpreter/interp_masm.hpp" #include "runtime/sharedRuntime.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif #define __ masm-> @@ -406,4 +411,209 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value __ bind(Ldone); } +#ifdef COMPILER1 + #undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + __ bind(*stub->entry()); + ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots. + assert(stub->pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); + } + + __ z_ltgr(Z_R1_scratch, pre_val_reg); // Pass oop in Z_R1_scratch to Runtime1::g1_pre_barrier_slow_id. + __ branch_optimized(Assembler::bcondZero, *stub->continuation()); + ce->emit_call_c(bs->pre_barrier_c1_runtime_code_blob()->code_begin()); + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots. + assert(stub->addr()->is_register(), "Precondition."); + assert(stub->new_val()->is_register(), "Precondition."); + Register new_val_reg = stub->new_val()->as_register(); + __ z_ltgr(new_val_reg, new_val_reg); + __ branch_optimized(Assembler::bcondZero, *stub->continuation()); + __ z_lgr(Z_R1_scratch, stub->addr()->as_pointer_register()); + ce->emit_call_c(bs->post_barrier_c1_runtime_code_blob()->code_begin()); + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); +} + +#undef __ + +#define __ sasm-> + +static OopMap* save_volatile_registers(StubAssembler* sasm, Register return_pc = Z_R14) { + __ block_comment("save_volatile_registers"); + RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers; + int frame_size_in_slots = RegisterSaver::live_reg_frame_size(reg_set) / VMRegImpl::stack_slot_size; + sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word); + return RegisterSaver::save_live_registers(sasm, reg_set, return_pc); +} + +static void restore_volatile_registers(StubAssembler* sasm) { + __ block_comment("restore_volatile_registers"); + RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers; + RegisterSaver::restore_live_registers(sasm, reg_set); +} + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + // Z_R1_scratch: previous value of memory + + BarrierSet* bs = BarrierSet::barrier_set(); + __ set_info("g1_pre_barrier_slow_id", false); + + Register pre_val = Z_R1_scratch; + Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val. + Register tmp2 = Z_R7; + + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); + int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); + int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); + + // Save tmp registers (see assertion in G1PreBarrierStub::emit_code()). + __ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + __ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } + __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently. + + __ bind(restart); + // Load the index into the SATB buffer. SATBMarkQueue::_index is a + // size_t so ld_ptr is appropriate. + __ z_ltg(tmp, satb_q_index_byte_offset, Z_R0, Z_thread); + + // index == 0? + __ z_brz(refill); + + __ z_lg(tmp2, satb_q_buf_byte_offset, Z_thread); + __ add2reg(tmp, -oopSize); + + __ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := + __ z_stg(tmp, satb_q_index_byte_offset, Z_thread); + + __ bind(marking_not_active); + // Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()). + __ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + __ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + __ z_br(Z_R14); + + __ bind(refill); + save_volatile_registers(sasm); + __ z_lgr(tmp, pre_val); // save pre_val + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), + Z_thread); + __ z_lgr(pre_val, tmp); // restore pre_val + restore_volatile_registers(sasm); + __ z_bru(restart); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + // Z_R1_scratch: oop address, address of updated memory slot + + BarrierSet* bs = BarrierSet::barrier_set(); + __ set_info("g1_post_barrier_slow_id", false); + + Register addr_oop = Z_R1_scratch; + Register addr_card = Z_R1_scratch; + Register r1 = Z_R6; // Must be saved/restored. + Register r2 = Z_R7; // Must be saved/restored. + Register cardtable = r1; // Must be non-volatile, because it is used to save addr_card. + CardTableBarrierSet* ctbs = barrier_set_cast(bs); + CardTable* ct = ctbs->card_table(); + jbyte* byte_map_base = ct->byte_map_base(); + + // Save registers used below (see assertion in G1PreBarrierStub::emit_code()). + __ z_stg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + + Label not_already_dirty, restart, refill, young_card; + + // Calculate address of card corresponding to the updated oop slot. + AddressLiteral rs(byte_map_base); + __ z_srlg(addr_card, addr_oop, CardTable::card_shift); + addr_oop = noreg; // dead now + __ load_const_optimized(cardtable, rs); // cardtable := + __ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable + + __ z_cli(0, addr_card, (int)G1CardTable::g1_young_card_val()); + __ z_bre(young_card); + + __ z_sync(); // Required to support concurrent cleaning. + + __ z_cli(0, addr_card, (int)CardTable::dirty_card_val()); + __ z_brne(not_already_dirty); + + __ bind(young_card); + // We didn't take the branch, so we're already dirty: restore + // used registers and return. + __ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + __ z_br(Z_R14); + + // Not dirty. + __ bind(not_already_dirty); + + // First, dirty it: [addr_card] := 0 + __ z_mvi(0, addr_card, CardTable::dirty_card_val()); + + Register idx = cardtable; // Must be non-volatile, because it is used to save addr_card. + Register buf = r2; + cardtable = noreg; // now dead + + // Save registers used below (see assertion in G1PreBarrierStub::emit_code()). + __ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + + ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset(); + ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset(); + + __ bind(restart); + + // Get the index into the update buffer. DirtyCardQueue::_index is + // a size_t so z_ltg is appropriate here. + __ z_ltg(idx, Address(Z_thread, dirty_card_q_index_byte_offset)); + + // index == 0? + __ z_brz(refill); + + __ z_lg(buf, Address(Z_thread, dirty_card_q_buf_byte_offset)); + __ add2reg(idx, -oopSize); + + __ z_stg(addr_card, 0, idx, buf); // [_buf + index] := + __ z_stg(idx, Address(Z_thread, dirty_card_q_index_byte_offset)); + // Restore killed registers and return. + __ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + __ z_lg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + __ z_br(Z_R14); + + __ bind(refill); + save_volatile_registers(sasm); + __ z_lgr(idx, addr_card); // Save addr_card, tmp3 must be non-volatile. + __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), + Z_thread); + __ z_lgr(addr_card, idx); + restore_volatile_registers(sasm); // Restore addr_card. + __ z_bru(restart); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp index a9d500492de..ad66ef0f37c 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp @@ -28,6 +28,12 @@ #include "asm/macroAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "utilities/macros.hpp" + +class LIR_Assembler; +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -50,6 +56,14 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3); public: +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); +#endif + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, const Address& src, Register dst, Register tmp1, Register tmp2, Label *is_null = NULL); diff --git a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp index 787540ea676..706ca930a72 100644 --- a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp @@ -32,9 +32,6 @@ #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" #include "vmreg_sparc.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -454,63 +451,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ delayed()->nop(); } - -/////////////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that marking is in progress. - // If do_load() is true then we have to emit the - // load of the previous value; otherwise it has already - // been loaded into _pre_val. - - __ bind(_entry); - - assert(pre_val()->is_register(), "Precondition."); - Register pre_val_reg = pre_val()->as_register(); - - if (do_load()) { - ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); - } - - if (__ is_in_wdisp16_range(_continuation)) { - __ br_null(pre_val_reg, /*annul*/false, Assembler::pt, _continuation); - } else { - __ cmp(pre_val_reg, G0); - __ brx(Assembler::equal, false, Assembler::pn, _continuation); - } - __ delayed()->nop(); - - __ call(Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id)); - __ delayed()->mov(pre_val_reg, G4); - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->nop(); - -} - -void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - - assert(addr()->is_register(), "Precondition."); - assert(new_val()->is_register(), "Precondition."); - Register addr_reg = addr()->as_pointer_register(); - Register new_val_reg = new_val()->as_register(); - - if (__ is_in_wdisp16_range(_continuation)) { - __ br_null(new_val_reg, /*annul*/false, Assembler::pt, _continuation); - } else { - __ cmp(new_val_reg, G0); - __ brx(Assembler::equal, false, Assembler::pn, _continuation); - } - __ delayed()->nop(); - - __ call(Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id)); - __ delayed()->mov(addr_reg, G4); - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->nop(); -} - -#endif // INCLUDE_ALL_GCS -/////////////////////////////////////////////////////////////////////////////////// - #undef __ diff --git a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp index 8c4978c0129..129e1899e19 100644 --- a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp @@ -193,7 +193,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type, bool needs_card_mark) { + BasicType type) { int elem_size = type2aelembytes(type); int shift = exact_log2(elem_size); @@ -231,13 +231,8 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o __ add(index_opr, array_opr, base_opr); } } - if (needs_card_mark) { - LIR_Opr ptr = new_pointer_register(); - __ add(base_opr, LIR_OprFact::intptrConst(offset), ptr); - return new LIR_Address(ptr, type); - } else { - return new LIR_Address(base_opr, offset, type); - } + + return new LIR_Address(base_opr, offset, type); } LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { @@ -311,86 +306,17 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) } } +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { + LIR_Opr tmp1 = FrameMap::G1_opr; + LIR_Opr tmp2 = FrameMap::G3_opr; + LIR_Opr tmp3 = FrameMap::G5_opr; + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); +} + //---------------------------------------------------------------------- // visitor functions //---------------------------------------------------------------------- - -void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { - assert(x->is_pinned(),""); - bool needs_range_check = x->compute_needs_range_check(); - bool use_length = x->length() != NULL; - bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || - !get_jobject_constant(x->value())->is_null_object() || - x->should_profile()); - - LIRItem array(x->array(), this); - LIRItem index(x->index(), this); - LIRItem value(x->value(), this); - LIRItem length(this); - - array.load_item(); - index.load_nonconstant(); - - if (use_length && needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } - if (needs_store_check || x->check_boolean()) { - value.load_item(); - } else { - value.load_for_store(x->elt_type()); - } - - set_no_result(x); - - // the CodeEmitInfo must be duplicated for each different - // LIR-instruction because spilling can occur anywhere between two - // instructions and so the debug information must be different - CodeEmitInfo* range_check_info = state_for(x); - CodeEmitInfo* null_check_info = NULL; - if (x->needs_null_check()) { - null_check_info = new CodeEmitInfo(range_check_info); - } - - // emit array address setup early so it schedules better - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); - - if (GenerateRangeChecks && needs_range_check) { - if (use_length) { - __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); - } else { - array_range_check(array.result(), index.result(), null_check_info, range_check_info); - // range_check also does the null check - null_check_info = NULL; - } - } - - if (GenerateArrayStoreCheck && needs_store_check) { - LIR_Opr tmp1 = FrameMap::G1_opr; - LIR_Opr tmp2 = FrameMap::G3_opr; - LIR_Opr tmp3 = FrameMap::G5_opr; - - CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); - __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci()); - } - - if (obj_store) { - // Needs GC write barriers. - pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); - __ move(result, array_addr, null_check_info); - if (obj_store) { - // Precise card mark - post_barrier(LIR_OprFact::address(array_addr), value.result()); - } -} - - void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { assert(x->is_pinned(),""); LIRItem obj(x->obj(), this); @@ -635,51 +561,47 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { } } - -void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { - assert(x->number_of_arguments() == 4, "wrong type"); - LIRItem obj (x->argument_at(0), this); // object - LIRItem offset(x->argument_at(1), this); // offset of field - LIRItem cmp (x->argument_at(2), this); // value to compare with field - LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp - - // Use temps to avoid kills +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { + LIR_Opr result = new_register(T_INT); LIR_Opr t1 = FrameMap::G1_opr; LIR_Opr t2 = FrameMap::G3_opr; - LIR_Opr addr = new_pointer_register(); - - // get address of field - obj.load_item(); - offset.load_item(); - cmp.load_item(); - val.load_item(); - - __ add(obj.result(), offset.result(), addr); - - if (type == objectType) { // Write-barrier needed for Object fields. - pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); + cmp_value.load_item(); + new_value.load_item(); + if (type == T_OBJECT || type == T_ARRAY) { + __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else if (type == T_INT) { + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else if (type == T_LONG) { + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); + } else { + Unimplemented(); } - - if (type == objectType) - __ cas_obj(addr, cmp.result(), val.result(), t1, t2); - else if (type == intType) - __ cas_int(addr, cmp.result(), val.result(), t1, t2); - else if (type == longType) - __ cas_long(addr, cmp.result(), val.result(), t1, t2); - else { - ShouldNotReachHere(); - } - // generate conditional move of boolean result - LIR_Opr result = rlock_result(x); __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), - result, as_BasicType(type)); - if (type == objectType) { // Write-barrier needed for Object fields. - // Precise card mark since could either be object or array - post_barrier(addr, val.result()); - } + result, type); + return result; } +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + bool is_obj = type == T_OBJECT || type == T_ARRAY; + LIR_Opr result = new_register(type); + LIR_Opr tmp = LIR_OprFact::illegalOpr; + + value.load_item(); + + if (is_obj) { + tmp = FrameMap::G3_opr; + } + + // Because we want a 2-arg form of xchg + __ move(value.result(), result); + __ xchg(addr, result, result, tmp); + return result; +} + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + Unimplemented(); + return LIR_OprFact::illegalOpr; +} void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { switch (x->id()) { @@ -1338,94 +1260,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { __ load(address, result, info); } - - -void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, - BasicType type, bool is_volatile) { - LIR_Opr base_op = src; - LIR_Opr index_op = offset; - - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - { - if (type == T_BOOLEAN) { - type = T_BYTE; - } - LIR_Address* addr; - if (type == T_ARRAY || type == T_OBJECT) { - LIR_Opr tmp = new_pointer_register(); - __ add(base_op, index_op, tmp); - addr = new LIR_Address(tmp, type); - } else { - addr = new LIR_Address(base_op, index_op, type); - } - - if (is_obj) { - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - // _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr)); - } - __ move(data, addr); - if (is_obj) { - // This address is precise - post_barrier(LIR_OprFact::address(addr), data); - } - } -} - - -void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, - BasicType type, bool is_volatile) { - { - LIR_Address* addr = new LIR_Address(src, offset, type); - __ load(addr, dst); - } -} - -void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { - BasicType type = x->basic_type(); - LIRItem src(x->object(), this); - LIRItem off(x->offset(), this); - LIRItem value(x->value(), this); - - src.load_item(); - value.load_item(); - off.load_nonconstant(); - - LIR_Opr dst = rlock_result(x, type); - LIR_Opr data = value.result(); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - LIR_Opr offset = off.result(); - - // Because we want a 2-arg form of xchg - __ move(data, dst); - - assert (!x->is_add() && (type == T_INT || (is_obj && UseCompressedOops)), "unexpected type"); - LIR_Address* addr; - if (offset->is_constant()) { - - jlong l = offset->as_jlong(); - assert((jlong)((jint)l) == l, "offset too large for constant"); - jint c = (jint)l; - addr = new LIR_Address(src.result(), c, type); - } else { - addr = new LIR_Address(src.result(), offset, type); - } - - LIR_Opr tmp = LIR_OprFact::illegalOpr; - LIR_Opr ptr = LIR_OprFact::illegalOpr; - - if (is_obj) { - // Do the pre-write barrier, if any. - // barriers on sparc don't work with a base + index address - tmp = FrameMap::G3_opr; - ptr = new_pointer_register(); - __ add(src.result(), off.result(), ptr); - pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - __ xchg(LIR_OprFact::address(addr), dst, dst, tmp); - if (is_obj) { - // Seems to be a precise address - post_barrier(ptr, data); - } -} diff --git a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp index 695ac7f4d27..ad669c3bfc2 100644 --- a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,4 +92,7 @@ // This platform only uses signal-based null checks. The Label is not needed. void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); } + void save_live_registers_no_oop_map(bool save_fpu_registers); + void restore_live_registers(bool restore_fpu_registers); + #endif // CPU_SPARC_VM_C1_MACROASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp index 29315e54f60..57bc7be205d 100644 --- a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp @@ -40,11 +40,6 @@ #include "utilities/macros.hpp" #include "utilities/align.hpp" #include "vmreg_sparc.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#endif // Implementation of StubAssembler @@ -145,10 +140,16 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre return call_RT(oop_result1, metadata_result, entry, 3); } +void StubAssembler::prologue(const char* name, bool must_gc_arguments) { + set_info(name, must_gc_arguments); +} + +void StubAssembler::epilogue() { + delayed()->restore(); +} // Implementation of Runtime1 -#define __ sasm-> static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs]; static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs]; @@ -156,7 +157,7 @@ static int reg_save_size_in_words; static int frame_size_in_bytes = -1; static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { - assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words), + assert(frame_size_in_bytes == sasm->total_frame_size_in_bytes(reg_save_size_in_words), "mismatch in calculation"); sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); @@ -183,7 +184,9 @@ static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { return oop_map; } -static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) { +#define __ this-> + +void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) { assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words), "mismatch in calculation"); __ save_frame_c1(frame_size_in_bytes); @@ -211,11 +214,9 @@ static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers __ stf(FloatRegisterImpl::S, r, SP, (sp_offset * BytesPerWord) + STACK_BIAS); } } - - return generate_oop_map(sasm, save_fpu_registers); } -static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { +void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) { for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { Register r = as_Register(i); if (r == G1 || r == G3 || r == G4 || r == G5) { @@ -231,6 +232,18 @@ static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registe } } +#undef __ +#define __ sasm-> + +static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) { + sasm->save_live_registers_no_oop_map(save_fpu_registers); + return generate_oop_map(sasm, save_fpu_registers); +} + +static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { + sasm->restore_live_registers(restore_fpu_registers); +} + void Runtime1::initialize_pd() { // compute word offsets from SP at which live (non-windowed) registers are captured by stub routines @@ -759,165 +772,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#if INCLUDE_ALL_GCS - case g1_pre_barrier_slow_id: - { // G4: previous value of memory - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ save_frame(0); - __ set((int)id, O1); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), I0); - __ should_not_reach_here(); - break; - } - - __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); - - Register pre_val = G4; - Register tmp = G1_scratch; - Register tmp2 = G3_scratch; - - Label refill, restart; - int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ld(G2_thread, satb_q_active_byte_offset, tmp); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldsb(G2_thread, satb_q_active_byte_offset, tmp); - } - __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart); - __ retl(); - __ delayed()->nop(); - - __ bind(restart); - // Load the index into the SATB buffer. SATBMarkQueue::_index is a - // size_t so ld_ptr is appropriate - __ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp); - - // index == 0? - __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pn, refill); - - __ ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2); - __ sub(tmp, oopSize, tmp); - - __ st_ptr(pre_val, tmp2, tmp); // [_buf + index] := - // Use return-from-leaf - __ retl(); - __ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset); - - __ bind(refill); - - save_live_registers(sasm); - - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, - SATBMarkQueueSet::handle_zero_index_for_thread), - G2_thread); - - restore_live_registers(sasm); - - __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); - __ delayed()->restore(); - } - break; - - case g1_post_barrier_slow_id: - { - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ save_frame(0); - __ set((int)id, O1); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), I0); - __ should_not_reach_here(); - break; - } - - __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); - - Register addr = G4; - Register cardtable = G5; - Register tmp = G1_scratch; - Register tmp2 = G3_scratch; - jbyte* byte_map_base = ci_card_table_address(); - - Label not_already_dirty, restart, refill, young_card; - - __ srlx(addr, CardTable::card_shift, addr); - - AddressLiteral rs(byte_map_base); - __ set(rs, cardtable); // cardtable := - __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] - - __ cmp_and_br_short(tmp, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); - - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); - __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] - - assert(CardTable::dirty_card_val() == 0, "otherwise check this code"); - __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); - - __ bind(young_card); - // We didn't take the branch, so we're already dirty: return. - // Use return-from-leaf - __ retl(); - __ delayed()->nop(); - - // Not dirty. - __ bind(not_already_dirty); - - // Get cardtable + tmp into a reg by itself - __ add(addr, cardtable, tmp2); - - // First, dirty it. - __ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty). - - Register tmp3 = cardtable; - Register tmp4 = tmp; - - // these registers are now dead - addr = cardtable = tmp = noreg; - - int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - - __ bind(restart); - - // Get the index into the update buffer. DirtyCardQueue::_index is - // a size_t so ld_ptr is appropriate here. - __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3); - - // index == 0? - __ cmp_and_brx_short(tmp3, G0, Assembler::equal, Assembler::pn, refill); - - __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4); - __ sub(tmp3, oopSize, tmp3); - - __ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] := - // Use return-from-leaf - __ retl(); - __ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset); - - __ bind(refill); - - save_live_registers(sasm); - - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, - DirtyCardQueueSet::handle_zero_index_for_thread), - G2_thread); - - restore_live_registers(sasm); - - __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); - __ delayed()->restore(); - } - break; -#endif // INCLUDE_ALL_GCS - case predicate_failed_trap_id: { __ set_info("predicate_failed_trap", dont_gc_arguments); diff --git a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp index e282dc31848..1de5dfea13e 100644 --- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp @@ -25,13 +25,18 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" +#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/heapRegion.hpp" #include "interpreter/interp_masm.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif #define __ masm-> @@ -476,8 +481,6 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator } } -#undef __ - void G1BarrierSetAssembler::barrier_stubs_init() { if (dirty_card_log_enqueue == 0) { G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); @@ -494,3 +497,211 @@ void G1BarrierSetAssembler::barrier_stubs_init() { assert(satb_log_enqueue_frameless != 0, "postcondition."); } } + +#ifdef COMPILER1 + +#undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(*stub->entry()); + + assert(stub->pre_val()->is_register(), "Precondition."); + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); + } + + if (__ is_in_wdisp16_range(*stub->continuation())) { + __ br_null(pre_val_reg, /*annul*/false, Assembler::pt, *stub->continuation()); + } else { + __ cmp(pre_val_reg, G0); + __ brx(Assembler::equal, false, Assembler::pn, *stub->continuation()); + } + __ delayed()->nop(); + + __ call(bs->pre_barrier_c1_runtime_code_blob()->code_begin()); + __ delayed()->mov(pre_val_reg, G4); + __ br(Assembler::always, false, Assembler::pt, *stub->continuation()); + __ delayed()->nop(); +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + + assert(stub->addr()->is_register(), "Precondition."); + assert(stub->new_val()->is_register(), "Precondition."); + Register addr_reg = stub->addr()->as_pointer_register(); + Register new_val_reg = stub->new_val()->as_register(); + + if (__ is_in_wdisp16_range(*stub->continuation())) { + __ br_null(new_val_reg, /*annul*/false, Assembler::pt, *stub->continuation()); + } else { + __ cmp(new_val_reg, G0); + __ brx(Assembler::equal, false, Assembler::pn, *stub->continuation()); + } + __ delayed()->nop(); + + __ call(bs->post_barrier_c1_runtime_code_blob()->code_begin()); + __ delayed()->mov(addr_reg, G4); + __ br(Assembler::always, false, Assembler::pt, *stub->continuation()); + __ delayed()->nop(); +} + +#undef __ +#define __ sasm-> + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_pre_barrier", false); + + // G4: previous value of memory + + Register pre_val = G4; + Register tmp = G1_scratch; + Register tmp2 = G3_scratch; + + Label refill, restart; + int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); + int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); + int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); + + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ld(G2_thread, satb_q_active_byte_offset, tmp); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldsb(G2_thread, satb_q_active_byte_offset, tmp); + } + __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart); + __ retl(); + __ delayed()->nop(); + + __ bind(restart); + // Load the index into the SATB buffer. SATBMarkQueue::_index is a + // size_t so ld_ptr is appropriate + __ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp); + + // index == 0? + __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pn, refill); + + __ ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2); + __ sub(tmp, oopSize, tmp); + + __ st_ptr(pre_val, tmp2, tmp); // [_buf + index] := + // Use return-from-leaf + __ retl(); + __ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset); + + __ bind(refill); + + __ save_live_registers_no_oop_map(true); + + __ call_VM_leaf(L7_thread_cache, + CAST_FROM_FN_PTR(address, + SATBMarkQueueSet::handle_zero_index_for_thread), + G2_thread); + + __ restore_live_registers(true); + + __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); + __ epilogue(); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_post_barrier", false); + + G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); + + Register addr = G4; + Register cardtable = G5; + Register tmp = G1_scratch; + Register tmp2 = G3_scratch; + jbyte* byte_map_base = bs->card_table()->byte_map_base(); + + Label not_already_dirty, restart, refill, young_card; + +#ifdef _LP64 + __ srlx(addr, CardTable::card_shift, addr); +#else + __ srl(addr, CardTable::card_shift, addr); +#endif + + AddressLiteral rs((address)byte_map_base); + __ set(rs, cardtable); // cardtable := + __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] + + __ cmp_and_br_short(tmp, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] + + assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code"); + __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); + + __ bind(young_card); + // We didn't take the branch, so we're already dirty: return. + // Use return-from-leaf + __ retl(); + __ delayed()->nop(); + + // Not dirty. + __ bind(not_already_dirty); + + // Get cardtable + tmp into a reg by itself + __ add(addr, cardtable, tmp2); + + // First, dirty it. + __ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty). + + Register tmp3 = cardtable; + Register tmp4 = tmp; + + // these registers are now dead + addr = cardtable = tmp = noreg; + + int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); + int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); + + __ bind(restart); + + // Get the index into the update buffer. DirtyCardQueue::_index is + // a size_t so ld_ptr is appropriate here. + __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3); + + // index == 0? + __ cmp_and_brx_short(tmp3, G0, Assembler::equal, Assembler::pn, refill); + + __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4); + __ sub(tmp3, oopSize, tmp3); + + __ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] := + // Use return-from-leaf + __ retl(); + __ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset); + + __ bind(refill); + + __ save_live_registers_no_oop_map(true); + + __ call_VM_leaf(L7_thread_cache, + CAST_FROM_FN_PTR(address, + DirtyCardQueueSet::handle_zero_index_for_thread), + G2_thread); + + __ restore_live_registers(true); + + __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); + __ epilogue(); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp index 6ad0c3599c3..3c706b5e53a 100644 --- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp @@ -27,6 +27,12 @@ #include "asm/macroAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "utilities/macros.hpp" + +class LIR_Assembler; +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -40,6 +46,14 @@ protected: Register val, Address dst, Register tmp); public: +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); +#endif + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address src, Register dst, Register tmp); virtual void barrier_stubs_init(); diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index d2bc3c9e1ff..9bb1d7fb79d 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -33,9 +33,6 @@ #include "utilities/align.hpp" #include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -521,45 +518,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ jmp(_continuation); } -///////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that marking is in progress. - // If do_load() is true then we have to emit the - // load of the previous value; otherwise it has already - // been loaded into _pre_val. - - __ bind(_entry); - assert(pre_val()->is_register(), "Precondition."); - - Register pre_val_reg = pre_val()->as_register(); - - if (do_load()) { - ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); - } - - __ cmpptr(pre_val_reg, (int32_t) NULL_WORD); - __ jcc(Assembler::equal, _continuation); - ce->store_parameter(pre_val()->as_register(), 0); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id))); - __ jmp(_continuation); - -} - -void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - assert(addr()->is_register(), "Precondition."); - assert(new_val()->is_register(), "Precondition."); - Register new_val_reg = new_val()->as_register(); - __ cmpptr(new_val_reg, (int32_t) NULL_WORD); - __ jcc(Assembler::equal, _continuation); - ce->store_parameter(addr()->as_pointer_register(), 0); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id))); - __ jmp(_continuation); -} - -#endif // INCLUDE_ALL_GCS -///////////////////////////////////////////////////////////////////////////// - #undef __ diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 709ee0a3f5e..5e4e8e21536 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -33,6 +33,7 @@ #include "ci/ciArray.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "gc/shared/c1/barrierSetC1.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "vmreg_x86.inline.hpp" @@ -152,9 +153,27 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, int shift, int disp, BasicType type) { assert(base->is_register(), "must be"); if (index->is_constant()) { + LIR_Const *constant = index->as_constant_ptr(); +#ifdef _LP64 + jlong c; + if (constant->type() == T_INT) { + c = (jlong(index->as_jint()) << shift) + disp; + } else { + assert(constant->type() == T_LONG, "should be"); + c = (index->as_jlong() << shift) + disp; + } + if ((jlong)((jint)c) == c) { + return new LIR_Address(base, (jint)c, type); + } else { + LIR_Opr tmp = new_register(T_LONG); + __ move(index, tmp); + return new LIR_Address(base, tmp, type); + } +#else return new LIR_Address(base, - ((intx)(index->as_constant_ptr()->as_jint()) << shift) + disp, + ((intx)(constant->as_jint()) << shift) + disp, type); +#endif } else { return new LIR_Address(base, index, (LIR_Address::Scale)shift, disp, type); } @@ -162,7 +181,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type, bool needs_card_mark) { + BasicType type) { int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type); LIR_Address* addr; @@ -183,16 +202,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o LIR_Address::scale(type), offset_in_bytes, type); } - if (needs_card_mark) { - // This store will need a precise card mark, so go ahead and - // compute the full adddres instead of computing once for the - // store and again for the card mark. - LIR_Opr tmp = new_pointer_register(); - __ leal(LIR_OprFact::address(addr), tmp); - return new LIR_Address(tmp, type); - } else { - return addr; - } + return addr; } @@ -253,87 +263,17 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) __ store(item, new LIR_Address(FrameMap::rsp_opr, in_bytes(offset_from_sp), type)); } +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { + LIR_Opr tmp1 = new_register(objectType); + LIR_Opr tmp2 = new_register(objectType); + LIR_Opr tmp3 = new_register(objectType); + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); +} + //---------------------------------------------------------------------- // visitor functions //---------------------------------------------------------------------- - -void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { - assert(x->is_pinned(),""); - bool needs_range_check = x->compute_needs_range_check(); - bool use_length = x->length() != NULL; - bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || - !get_jobject_constant(x->value())->is_null_object() || - x->should_profile()); - - LIRItem array(x->array(), this); - LIRItem index(x->index(), this); - LIRItem value(x->value(), this); - LIRItem length(this); - - array.load_item(); - index.load_nonconstant(); - - if (use_length && needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - - } - if (needs_store_check || x->check_boolean()) { - value.load_item(); - } else { - value.load_for_store(x->elt_type()); - } - - set_no_result(x); - - // the CodeEmitInfo must be duplicated for each different - // LIR-instruction because spilling can occur anywhere between two - // instructions and so the debug information must be different - CodeEmitInfo* range_check_info = state_for(x); - CodeEmitInfo* null_check_info = NULL; - if (x->needs_null_check()) { - null_check_info = new CodeEmitInfo(range_check_info); - } - - // emit array address setup early so it schedules better - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); - - if (GenerateRangeChecks && needs_range_check) { - if (use_length) { - __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); - } else { - array_range_check(array.result(), index.result(), null_check_info, range_check_info); - // range_check also does the null check - null_check_info = NULL; - } - } - - if (GenerateArrayStoreCheck && needs_store_check) { - LIR_Opr tmp1 = new_register(objectType); - LIR_Opr tmp2 = new_register(objectType); - LIR_Opr tmp3 = new_register(objectType); - - CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); - __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci()); - } - - if (obj_store) { - // Needs GC write barriers. - pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - __ move(value.result(), array_addr, null_check_info); - // Seems to be a precise - post_barrier(LIR_OprFact::address(array_addr), value.result()); - } else { - LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info); - __ move(result, array_addr, null_check_info); - } -} - - void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { assert(x->is_pinned(),""); LIRItem obj(x->obj(), this); @@ -715,93 +655,48 @@ void LIRGenerator::do_CompareOp(CompareOp* x) { } } - -void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { - assert(x->number_of_arguments() == 4, "wrong type"); - LIRItem obj (x->argument_at(0), this); // object - LIRItem offset(x->argument_at(1), this); // offset of field - LIRItem cmp (x->argument_at(2), this); // value to compare with field - LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp - - assert(obj.type()->tag() == objectTag, "invalid type"); - - // In 64bit the type can be long, sparc doesn't have this assert - // assert(offset.type()->tag() == intTag, "invalid type"); - - assert(cmp.type()->tag() == type->tag(), "invalid type"); - assert(val.type()->tag() == type->tag(), "invalid type"); - - // get address of field - obj.load_item(); - offset.load_nonconstant(); - - LIR_Opr addr = new_pointer_register(); - LIR_Address* a; - if(offset.result()->is_constant()) { -#ifdef _LP64 - jlong c = offset.result()->as_jlong(); - if ((jlong)((jint)c) == c) { - a = new LIR_Address(obj.result(), - (jint)c, - as_BasicType(type)); - } else { - LIR_Opr tmp = new_register(T_LONG); - __ move(offset.result(), tmp); - a = new LIR_Address(obj.result(), - tmp, - as_BasicType(type)); - } -#else - a = new LIR_Address(obj.result(), - offset.result()->as_jint(), - as_BasicType(type)); -#endif - } else { - a = new LIR_Address(obj.result(), - offset.result(), - 0, - as_BasicType(type)); - } - __ leal(LIR_OprFact::address(a), addr); - - if (type == objectType) { // Write-barrier needed for Object fields. - // Do the pre-write barrier, if any. - pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - - if (type == objectType) { - cmp.load_item_force(FrameMap::rax_oop_opr); - val.load_item(); - } else if (type == intType) { - cmp.load_item_force(FrameMap::rax_opr); - val.load_item(); - } else if (type == longType) { - cmp.load_item_force(FrameMap::long0_opr); - val.load_item_force(FrameMap::long1_opr); - } else { - ShouldNotReachHere(); - } - +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience - if (type == objectType) - __ cas_obj(addr, cmp.result(), val.result(), ill, ill); - else if (type == intType) - __ cas_int(addr, cmp.result(), val.result(), ill, ill); - else if (type == longType) - __ cas_long(addr, cmp.result(), val.result(), ill, ill); - else { - ShouldNotReachHere(); + if (type == T_OBJECT || type == T_ARRAY) { + cmp_value.load_item_force(FrameMap::rax_oop_opr); + new_value.load_item(); + __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else if (type == T_INT) { + cmp_value.load_item_force(FrameMap::rax_opr); + new_value.load_item(); + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else if (type == T_LONG) { + cmp_value.load_item_force(FrameMap::long0_opr); + new_value.load_item_force(FrameMap::long1_opr); + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else { + Unimplemented(); } - - // generate conditional move of boolean result - LIR_Opr result = rlock_result(x); + LIR_Opr result = new_register(T_INT); __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), - result, as_BasicType(type)); - if (type == objectType) { // Write-barrier needed for Object fields. - // Seems to be precise - post_barrier(addr, val.result()); - } + result, type); + return result; +} + +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + bool is_oop = type == T_OBJECT || type == T_ARRAY; + LIR_Opr result = new_register(type); + value.load_item(); + // Because we want a 2-arg form of xchg and xadd + __ move(value.result(), result); + assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); + __ xchg(addr, result, result, LIR_OprFact::illegalOpr); + return result; +} + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + value.load_item(); + // Because we want a 2-arg form of xchg and xadd + __ move(value.result(), result); + assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type"); + __ xadd(addr, result, result, LIR_OprFact::illegalOpr); + return result; } void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) { @@ -1570,8 +1465,6 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, } } - - void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { if (address->type() == T_LONG) { @@ -1593,100 +1486,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, __ load(address, result, info); } } - -void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, - BasicType type, bool is_volatile) { - if (is_volatile && type == T_LONG) { - LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE); - LIR_Opr tmp = new_register(T_DOUBLE); - __ load(addr, tmp); - LIR_Opr spill = new_register(T_LONG); - set_vreg_flag(spill, must_start_in_memory); - __ move(tmp, spill); - __ move(spill, dst); - } else { - LIR_Address* addr = new LIR_Address(src, offset, type); - __ load(addr, dst); - } -} - - -void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, - BasicType type, bool is_volatile) { - if (is_volatile && type == T_LONG) { - LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE); - LIR_Opr tmp = new_register(T_DOUBLE); - LIR_Opr spill = new_register(T_DOUBLE); - set_vreg_flag(spill, must_start_in_memory); - __ move(data, spill); - __ move(spill, tmp); - __ move(tmp, addr); - } else { - LIR_Address* addr = new LIR_Address(src, offset, type); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - if (is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - __ move(data, addr); - assert(src->is_register(), "must be register"); - // Seems to be a precise address - post_barrier(LIR_OprFact::address(addr), data); - } else { - __ move(data, addr); - } - } -} - -void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { - BasicType type = x->basic_type(); - LIRItem src(x->object(), this); - LIRItem off(x->offset(), this); - LIRItem value(x->value(), this); - - src.load_item(); - value.load_item(); - off.load_nonconstant(); - - LIR_Opr dst = rlock_result(x, type); - LIR_Opr data = value.result(); - bool is_obj = (type == T_ARRAY || type == T_OBJECT); - LIR_Opr offset = off.result(); - - assert (type == T_INT || (!x->is_add() && is_obj) LP64_ONLY( || type == T_LONG ), "unexpected type"); - LIR_Address* addr; - if (offset->is_constant()) { -#ifdef _LP64 - jlong c = offset->as_jlong(); - if ((jlong)((jint)c) == c) { - addr = new LIR_Address(src.result(), (jint)c, type); - } else { - LIR_Opr tmp = new_register(T_LONG); - __ move(offset, tmp); - addr = new LIR_Address(src.result(), tmp, type); - } -#else - addr = new LIR_Address(src.result(), offset->as_jint(), type); -#endif - } else { - addr = new LIR_Address(src.result(), offset, type); - } - - // Because we want a 2-arg form of xchg and xadd - __ move(data, dst); - - if (x->is_add()) { - __ xadd(LIR_OprFact::address(addr), dst, dst, LIR_OprFact::illegalOpr); - } else { - if (is_obj) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load */, false /* patch */, NULL); - } - __ xchg(LIR_OprFact::address(addr), dst, dst, LIR_OprFact::illegalOpr); - if (is_obj) { - // Seems to be a precise address - post_barrier(LIR_OprFact::address(addr), data); - } - } -} diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 3faf9de5a4b..020a3a253e0 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -356,6 +356,15 @@ void C1_MacroAssembler::verified_entry() { verify_FPU(0, "method_entry"); } +void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) { + // rbp, + 0: link + // + 1: return address + // + 2: argument with offset 0 + // + 3: argument with offset 1 + // + 4: ... + + movptr(reg, Address(rbp, (offset_in_words + 2) * BytesPerWord)); +} #ifndef PRODUCT diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp index 829db55b196..98bfe88491b 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,4 +121,9 @@ // This platform only uses signal-based null checks. The Label is not needed. void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); } + void load_parameter(int offset_in_words, Register reg); + + void save_live_registers_no_oop_map(int num_rt_args, bool save_fpu_registers); + void restore_live_registers(bool restore_fpu_registers); + #endif // CPU_X86_VM_C1_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index f02118c3ed4..9740ef99ffd 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -41,12 +41,6 @@ #include "runtime/vframeArray.hpp" #include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#endif - // Implementation of StubAssembler @@ -212,31 +206,32 @@ class StubFrame: public StackObj { ~StubFrame(); }; +void StubAssembler::prologue(const char* name, bool must_gc_arguments) { + set_info(name, must_gc_arguments); + enter(); +} + +void StubAssembler::epilogue() { + leave(); + ret(0); +} #define __ _sasm-> StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) { _sasm = sasm; - __ set_info(name, must_gc_arguments); - __ enter(); + __ prologue(name, must_gc_arguments); } // load parameters that were stored with LIR_Assembler::store_parameter // Note: offsets for store_parameter and load_argument must match void StubFrame::load_argument(int offset_in_words, Register reg) { - // rbp, + 0: link - // + 1: return address - // + 2: argument with offset 0 - // + 3: argument with offset 1 - // + 4: ... - - __ movptr(reg, Address(rbp, (offset_in_words + 2) * BytesPerWord)); + __ load_parameter(offset_in_words, reg); } StubFrame::~StubFrame() { - __ leave(); - __ ret(0); + __ epilogue(); } #undef __ @@ -244,8 +239,6 @@ StubFrame::~StubFrame() { // Implementation of Runtime1 -#define __ sasm-> - const int float_regs_as_doubles_size_in_slots = pd_nof_fpu_regs_frame_map * 2; const int xmm_regs_as_doubles_size_in_slots = FrameMap::nof_xmm_regs * 2; @@ -310,8 +303,6 @@ enum reg_save_layout { reg_save_frame_size // As noted: neglects any parameters to runtime // 504 }; - - // Save off registers which might be killed by calls into the runtime. // Tries to smart of about FP registers. In particular we separate // saving and describing the FPU registers for deoptimization since we @@ -418,8 +409,9 @@ static OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args, return map; } -static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args, - bool save_fpu_registers = true) { +#define __ this-> + +void C1_MacroAssembler::save_live_registers_no_oop_map(int num_rt_args, bool save_fpu_registers) { __ block_comment("save_live_registers"); __ pusha(); // integer registers @@ -493,12 +485,12 @@ static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args, // FPU stack must be empty now __ verify_FPU(0, "save_live_registers"); - - return generate_oop_map(sasm, num_rt_args, save_fpu_registers); } +#undef __ +#define __ sasm-> -static void restore_fpu(StubAssembler* sasm, bool restore_fpu_registers = true) { +static void restore_fpu(C1_MacroAssembler* sasm, bool restore_fpu_registers) { if (restore_fpu_registers) { if (UseSSE >= 2) { // restore XMM registers @@ -549,14 +541,28 @@ static void restore_fpu(StubAssembler* sasm, bool restore_fpu_registers = true) __ addptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size); } +#undef __ +#define __ this-> -static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { +void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) { __ block_comment("restore_live_registers"); - restore_fpu(sasm, restore_fpu_registers); + restore_fpu(this, restore_fpu_registers); __ popa(); } +#undef __ +#define __ sasm-> + +static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args, + bool save_fpu_registers = true) { + sasm->save_live_registers_no_oop_map(num_rt_args, save_fpu_registers); + return generate_oop_map(sasm, num_rt_args, save_fpu_registers); +} + +static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { + sasm->restore_live_registers(restore_fpu_registers); +} static void restore_live_registers_except_rax(StubAssembler* sasm, bool restore_fpu_registers = true) { __ block_comment("restore_live_registers_except_rax"); @@ -1557,159 +1563,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#if INCLUDE_ALL_GCS - case g1_pre_barrier_slow_id: - { - StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments); - // arg0 : previous value of memory - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ movptr(rax, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax); - __ should_not_reach_here(); - break; - } - __ push(rax); - __ push(rdx); - - const Register pre_val = rax; - const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); - const Register tmp = rdx; - - NOT_LP64(__ get_thread(thread);) - - Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - Label done; - Label runtime; - - // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ cmpl(queue_active, 0); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ cmpb(queue_active, 0); - } - __ jcc(Assembler::equal, done); - - // Can we store original value in the thread's buffer? - - __ movptr(tmp, queue_index); - __ testptr(tmp, tmp); - __ jcc(Assembler::zero, runtime); - __ subptr(tmp, wordSize); - __ movptr(queue_index, tmp); - __ addptr(tmp, buffer); - - // prev_val (rax) - f.load_argument(0, pre_val); - __ movptr(Address(tmp, 0), pre_val); - __ jmp(done); - - __ bind(runtime); - - save_live_registers(sasm, 3); - - // load the pre-value - f.load_argument(0, rcx); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), rcx, thread); - - restore_live_registers(sasm); - - __ bind(done); - - __ pop(rdx); - __ pop(rax); - } - break; - - case g1_post_barrier_slow_id: - { - StubFrame f(sasm, "g1_post_barrier", dont_gc_arguments); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ movptr(rax, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax); - __ should_not_reach_here(); - break; - } - - // arg0: store_address - Address store_addr(rbp, 2*BytesPerWord); - - Label done; - Label enqueued; - Label runtime; - - // At this point we know new_value is non-NULL and the new_value crosses regions. - // Must check to see if card is already dirty - - const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); - - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - __ push(rax); - __ push(rcx); - - const Register cardtable = rax; - const Register card_addr = rcx; - - f.load_argument(0, card_addr); - __ shrptr(card_addr, CardTable::card_shift); - // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT - // a valid address and therefore is not properly handled by the relocation code. - __ movptr(cardtable, ci_card_table_address_as()); - __ addptr(card_addr, cardtable); - - NOT_LP64(__ get_thread(thread);) - - __ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val()); - __ jcc(Assembler::equal, done); - - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); - __ cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val()); - __ jcc(Assembler::equal, done); - - // storing region crossing non-NULL, card is clean. - // dirty card and log. - - __ movb(Address(card_addr, 0), (int)CardTable::dirty_card_val()); - - const Register tmp = rdx; - __ push(rdx); - - __ movptr(tmp, queue_index); - __ testptr(tmp, tmp); - __ jcc(Assembler::zero, runtime); - __ subptr(tmp, wordSize); - __ movptr(queue_index, tmp); - __ addptr(tmp, buffer); - __ movptr(Address(tmp, 0), card_addr); - __ jmp(enqueued); - - __ bind(runtime); - - save_live_registers(sasm, 3); - - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread); - - restore_live_registers(sasm); - - __ bind(enqueued); - __ pop(rdx); - - __ bind(done); - __ pop(rcx); - __ pop(rax); - } - break; -#endif // INCLUDE_ALL_GCS - case predicate_failed_trap_id: { StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments); diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index ff8ee4bb6ad..1d63e8ec0f8 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -32,6 +32,11 @@ #include "interpreter/interp_masm.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif #define __ masm-> @@ -399,3 +404,193 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco } NOT_LP64(imasm->restore_bcp()); } + +#ifdef COMPILER1 + +#undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(*stub->entry()); + assert(stub->pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); + } + + __ cmpptr(pre_val_reg, (int32_t)NULL_WORD); + __ jcc(Assembler::equal, *stub->continuation()); + ce->store_parameter(stub->pre_val()->as_register(), 0); + __ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); + __ jmp(*stub->continuation()); + +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + assert(stub->addr()->is_register(), "Precondition."); + assert(stub->new_val()->is_register(), "Precondition."); + Register new_val_reg = stub->new_val()->as_register(); + __ cmpptr(new_val_reg, (int32_t) NULL_WORD); + __ jcc(Assembler::equal, *stub->continuation()); + ce->store_parameter(stub->addr()->as_pointer_register(), 0); + __ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin())); + __ jmp(*stub->continuation()); +} + +#undef __ + +#define __ sasm-> + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_pre_barrier", false); + // arg0 : previous value of memory + + __ push(rax); + __ push(rdx); + + const Register pre_val = rax; + const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); + const Register tmp = rdx; + + NOT_LP64(__ get_thread(thread);) + + Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + Label done; + Label runtime; + + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ cmpl(queue_active, 0); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ cmpb(queue_active, 0); + } + __ jcc(Assembler::equal, done); + + // Can we store original value in the thread's buffer? + + __ movptr(tmp, queue_index); + __ testptr(tmp, tmp); + __ jcc(Assembler::zero, runtime); + __ subptr(tmp, wordSize); + __ movptr(queue_index, tmp); + __ addptr(tmp, buffer); + + // prev_val (rax) + __ load_parameter(0, pre_val); + __ movptr(Address(tmp, 0), pre_val); + __ jmp(done); + + __ bind(runtime); + + __ save_live_registers_no_oop_map(3, true); + + // load the pre-value + __ load_parameter(0, rcx); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), rcx, thread); + + __ restore_live_registers(true); + + __ bind(done); + + __ pop(rdx); + __ pop(rax); + + __ epilogue(); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_post_barrier", false); + + // arg0: store_address + Address store_addr(rbp, 2*BytesPerWord); + + CardTableBarrierSet* ct = + barrier_set_cast(BarrierSet::barrier_set()); + assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code"); + + Label done; + Label enqueued; + Label runtime; + + // At this point we know new_value is non-NULL and the new_value crosses regions. + // Must check to see if card is already dirty + + const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); + + Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); + + __ push(rax); + __ push(rcx); + + const Register cardtable = rax; + const Register card_addr = rcx; + + __ load_parameter(0, card_addr); + __ shrptr(card_addr, CardTable::card_shift); + // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT + // a valid address and therefore is not properly handled by the relocation code. + __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base()); + __ addptr(card_addr, cardtable); + + NOT_LP64(__ get_thread(thread);) + + __ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val()); + __ jcc(Assembler::equal, done); + + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); + __ cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val()); + __ jcc(Assembler::equal, done); + + // storing region crossing non-NULL, card is clean. + // dirty card and log. + + __ movb(Address(card_addr, 0), (int)CardTable::dirty_card_val()); + + const Register tmp = rdx; + __ push(rdx); + + __ movptr(tmp, queue_index); + __ testptr(tmp, tmp); + __ jcc(Assembler::zero, runtime); + __ subptr(tmp, wordSize); + __ movptr(queue_index, tmp); + __ addptr(tmp, buffer); + __ movptr(Address(tmp, 0), card_addr); + __ jmp(enqueued); + + __ bind(runtime); + + __ save_live_registers_no_oop_map(3, true); + + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread); + + __ restore_live_registers(true); + + __ bind(enqueued); + __ pop(rdx); + + __ bind(done); + __ pop(rcx); + __ pop(rax); + + __ epilogue(); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp index 0aef8129209..94bbadc7b2b 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp @@ -28,6 +28,11 @@ #include "asm/macroAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +class LIR_Assembler; +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; + class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count); @@ -52,6 +57,12 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { Address dst, Register val, Register tmp1, Register tmp2); public: + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); }; diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp index 7156db40042..5bf61370370 100644 --- a/src/hotspot/share/c1/c1_CodeStubs.hpp +++ b/src/hotspot/share/c1/c1_CodeStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -533,92 +533,4 @@ class ArrayCopyStub: public CodeStub { #endif // PRODUCT }; -////////////////////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -// Code stubs for Garbage-First barriers. -class G1PreBarrierStub: public CodeStub { - private: - bool _do_load; - LIR_Opr _addr; - LIR_Opr _pre_val; - LIR_PatchCode _patch_code; - CodeEmitInfo* _info; - - public: - // Version that _does_ generate a load of the previous value from addr. - // addr (the address of the field to be read) must be a LIR_Address - // pre_val (a temporary register) must be a register; - G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) : - _addr(addr), _pre_val(pre_val), _do_load(true), - _patch_code(patch_code), _info(info) - { - assert(_pre_val->is_register(), "should be temporary register"); - assert(_addr->is_address(), "should be the address of the field"); - } - - // Version that _does not_ generate load of the previous value; the - // previous value is assumed to have already been loaded into pre_val. - G1PreBarrierStub(LIR_Opr pre_val) : - _addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false), - _patch_code(lir_patch_none), _info(NULL) - { - assert(_pre_val->is_register(), "should be a register"); - } - - LIR_Opr addr() const { return _addr; } - LIR_Opr pre_val() const { return _pre_val; } - LIR_PatchCode patch_code() const { return _patch_code; } - CodeEmitInfo* info() const { return _info; } - bool do_load() const { return _do_load; } - - virtual void emit_code(LIR_Assembler* e); - virtual void visit(LIR_OpVisitState* visitor) { - if (_do_load) { - // don't pass in the code emit info since it's processed in the fast - // path - if (_info != NULL) - visitor->do_slow_case(_info); - else - visitor->do_slow_case(); - - visitor->do_input(_addr); - visitor->do_temp(_pre_val); - } else { - visitor->do_slow_case(); - visitor->do_input(_pre_val); - } - } -#ifndef PRODUCT - virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); } -#endif // PRODUCT -}; - -class G1PostBarrierStub: public CodeStub { - private: - LIR_Opr _addr; - LIR_Opr _new_val; - - public: - // addr (the address of the object head) and new_val must be registers. - G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { } - - LIR_Opr addr() const { return _addr; } - LIR_Opr new_val() const { return _new_val; } - - virtual void emit_code(LIR_Assembler* e); - virtual void visit(LIR_OpVisitState* visitor) { - // don't pass in the code emit info since it's processed in the fast path - visitor->do_slow_case(); - visitor->do_input(_addr); - visitor->do_input(_new_val); - } -#ifndef PRODUCT - virtual void print_name(outputStream* out) const { out->print("G1PostBarrierStub"); } -#endif // PRODUCT -}; - -#endif // INCLUDE_ALL_GCS -////////////////////////////////////////////////////////////////////////////////////////// - #endif // SHARE_VM_C1_C1_CODESTUBS_HPP diff --git a/src/hotspot/share/c1/c1_Decorators.hpp b/src/hotspot/share/c1/c1_Decorators.hpp new file mode 100644 index 00000000000..a1020690e01 --- /dev/null +++ b/src/hotspot/share/c1/c1_Decorators.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_C1_C1_DECORATORS_HPP +#define SHARE_VM_C1_C1_DECORATORS_HPP + +#include "oops/accessDecorators.hpp" +#include "utilities/globalDefinitions.hpp" + +// Use the C1_NEEDS_PATCHING decorator for situations when the access is using +// an offset that is not yet known and will require patching +const DecoratorSet C1_NEEDS_PATCHING = DECORATOR_LAST << 1; +// Use the C1_MASK_BOOLEAN decorator for boolean accesses where the value +// needs to be masked. +const DecoratorSet C1_MASK_BOOLEAN = DECORATOR_LAST << 2; +// The C1_WRITE_ACCESS decorator is used to mark writing accesses. +const DecoratorSet C1_WRITE_ACCESS = DECORATOR_LAST << 3; +// The C1_READ_ACCESS decorator is used to mark reading accesses. +const DecoratorSet C1_READ_ACCESS = DECORATOR_LAST << 4; + +#endif // SHARE_VM_C1_C1_DECORATORS_HPP diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index 61dfbf3a337..6a0796b16fb 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,6 +260,8 @@ class LIR_Assembler: public CompilationResourceObj { #include CPU_HEADER(c1_LIRAssembler) + public: + static int call_stub_size() { if (UseAOT) { return _call_stub_size + _call_aot_stub_size; diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 32b5ce86cac..986dc61b8fc 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -34,19 +34,14 @@ #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" #include "ci/ciUtilities.hpp" -#include "gc/shared/cardTable.hpp" -#include "gc/shared/cardTableBarrierSet.hpp" -#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/c1/barrierSetC1.hpp" #include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/vm_version.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1ThreadLocalData.hpp" -#include "gc/g1/heapRegion.hpp" -#endif // INCLUDE_ALL_GCS #ifdef TRACE_HAVE_INTRINSICS #include "trace/traceMacros.hpp" #endif @@ -313,11 +308,6 @@ jlong LIRItem::get_jlong_constant() const { //-------------------------------------------------------------- -void LIRGenerator::init() { - _bs = BarrierSet::barrier_set(); -} - - void LIRGenerator::block_do_prolog(BlockBegin* block) { #ifndef PRODUCT if (PrintIRWithLIR) { @@ -1245,19 +1235,9 @@ void LIRGenerator::do_Reference_get(Intrinsic* x) { info = state_for(x); } - LIR_Address* referent_field_adr = - new LIR_Address(reference.result(), referent_offset, T_OBJECT); - - LIR_Opr result = rlock_result(x); - - __ load(referent_field_adr, result, info); - - // Register the value in the referent field with the pre-barrier - pre_barrier(LIR_OprFact::illegalOpr /* addr_opr */, - result /* pre_val */, - false /* do_load */, - false /* patch */, - NULL /* info */); + LIR_Opr result = rlock_result(x, T_OBJECT); + access_load_at(IN_HEAP | ON_WEAK_OOP_REF, T_OBJECT, + reference, LIR_OprFact::intConst(referent_offset), result); } // Example: clazz.isInstance(object) @@ -1454,222 +1434,27 @@ LIR_Opr LIRGenerator::load_constant(LIR_Const* c) { return result; } -// Various barriers - -void LIRGenerator::pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, - bool do_load, bool patch, CodeEmitInfo* info) { - // Do the pre-write barrier, if any. - switch (_bs->kind()) { -#if INCLUDE_ALL_GCS - case BarrierSet::G1BarrierSet: - G1BarrierSet_pre_barrier(addr_opr, pre_val, do_load, patch, info); - break; -#endif // INCLUDE_ALL_GCS - case BarrierSet::CardTableBarrierSet: - // No pre barriers - break; - default : - ShouldNotReachHere(); - - } -} - -void LIRGenerator::post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { - switch (_bs->kind()) { -#if INCLUDE_ALL_GCS - case BarrierSet::G1BarrierSet: - G1BarrierSet_post_barrier(addr, new_val); - break; -#endif // INCLUDE_ALL_GCS - case BarrierSet::CardTableBarrierSet: - CardTableBarrierSet_post_barrier(addr, new_val); - break; - default : - ShouldNotReachHere(); - } -} - -//////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -void LIRGenerator::G1BarrierSet_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, - bool do_load, bool patch, CodeEmitInfo* info) { - // First we test whether marking is in progress. - BasicType flag_type; - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - flag_type = T_INT; - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, - "Assumption"); - // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM, - // need to use unsigned instructions to use the large offset to load the satb_mark_queue. - flag_type = T_BOOLEAN; - } - LIR_Opr thrd = getThreadPointer(); - LIR_Address* mark_active_flag_addr = - new LIR_Address(thrd, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), flag_type); - // Read the marking-in-progress flag. - LIR_Opr flag_val = new_register(T_INT); - __ load(mark_active_flag_addr, flag_val); - __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); - - LIR_PatchCode pre_val_patch_code = lir_patch_none; - - CodeStub* slow; - - if (do_load) { - assert(pre_val == LIR_OprFact::illegalOpr, "sanity"); - assert(addr_opr != LIR_OprFact::illegalOpr, "sanity"); - - if (patch) - pre_val_patch_code = lir_patch_normal; - - pre_val = new_register(T_OBJECT); - - if (!addr_opr->is_address()) { - assert(addr_opr->is_register(), "must be"); - addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT)); - } - slow = new G1PreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info); - } else { - assert(addr_opr == LIR_OprFact::illegalOpr, "sanity"); - assert(pre_val->is_register(), "must be"); - assert(pre_val->type() == T_OBJECT, "must be an object"); - assert(info == NULL, "sanity"); - - slow = new G1PreBarrierStub(pre_val); - } - - __ branch(lir_cond_notEqual, T_INT, slow); - __ branch_destination(slow->continuation()); -} - -void LIRGenerator::G1BarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { - // If the "new_val" is a constant NULL, no barrier is necessary. - if (new_val->is_constant() && - new_val->as_constant_ptr()->as_jobject() == NULL) return; - - if (!new_val->is_register()) { - LIR_Opr new_val_reg = new_register(T_OBJECT); - if (new_val->is_constant()) { - __ move(new_val, new_val_reg); - } else { - __ leal(new_val, new_val_reg); - } - new_val = new_val_reg; - } - assert(new_val->is_register(), "must be a register at this point"); - - if (addr->is_address()) { - LIR_Address* address = addr->as_address_ptr(); - LIR_Opr ptr = new_pointer_register(); - if (!address->index()->is_valid() && address->disp() == 0) { - __ move(address->base(), ptr); - } else { - assert(address->disp() != max_jint, "lea doesn't support patched addresses!"); - __ leal(addr, ptr); - } - addr = ptr; - } - assert(addr->is_register(), "must be a register at this point"); - - LIR_Opr xor_res = new_pointer_register(); - LIR_Opr xor_shift_res = new_pointer_register(); - if (TwoOperandLIRForm ) { - __ move(addr, xor_res); - __ logical_xor(xor_res, new_val, xor_res); - __ move(xor_res, xor_shift_res); - __ unsigned_shift_right(xor_shift_res, - LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes), - xor_shift_res, - LIR_OprDesc::illegalOpr()); - } else { - __ logical_xor(addr, new_val, xor_res); - __ unsigned_shift_right(xor_res, - LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes), - xor_shift_res, - LIR_OprDesc::illegalOpr()); - } - - if (!new_val->is_register()) { - LIR_Opr new_val_reg = new_register(T_OBJECT); - __ leal(new_val, new_val_reg); - new_val = new_val_reg; - } - assert(new_val->is_register(), "must be a register at this point"); - - __ cmp(lir_cond_notEqual, xor_shift_res, LIR_OprFact::intptrConst(NULL_WORD)); - - CodeStub* slow = new G1PostBarrierStub(addr, new_val); - __ branch(lir_cond_notEqual, LP64_ONLY(T_LONG) NOT_LP64(T_INT), slow); - __ branch_destination(slow->continuation()); -} - -#endif // INCLUDE_ALL_GCS -//////////////////////////////////////////////////////////////////////// - -void LIRGenerator::CardTableBarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { - LIR_Const* card_table_base = new LIR_Const(ci_card_table_address()); - if (addr->is_address()) { - LIR_Address* address = addr->as_address_ptr(); - // ptr cannot be an object because we use this barrier for array card marks - // and addr can point in the middle of an array. - LIR_Opr ptr = new_pointer_register(); - if (!address->index()->is_valid() && address->disp() == 0) { - __ move(address->base(), ptr); - } else { - assert(address->disp() != max_jint, "lea doesn't support patched addresses!"); - __ leal(addr, ptr); - } - addr = ptr; - } - assert(addr->is_register(), "must be a register at this point"); - -#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER - CardTableBarrierSet_post_barrier_helper(addr, card_table_base); -#else - LIR_Opr tmp = new_pointer_register(); - if (TwoOperandLIRForm) { - __ move(addr, tmp); - __ unsigned_shift_right(tmp, CardTable::card_shift, tmp); - } else { - __ unsigned_shift_right(addr, CardTable::card_shift, tmp); - } - - LIR_Address* card_addr; - if (can_inline_as_constant(card_table_base)) { - card_addr = new LIR_Address(tmp, card_table_base->as_jint(), T_BYTE); - } else { - card_addr = new LIR_Address(tmp, load_constant(card_table_base), T_BYTE); - } - - LIR_Opr dirty = LIR_OprFact::intConst(CardTable::dirty_card_val()); - if (UseCondCardMark) { - LIR_Opr cur_value = new_register(T_INT); - if (UseConcMarkSweepGC) { - __ membar_storeload(); - } - __ move(card_addr, cur_value); - - LabelObj* L_already_dirty = new LabelObj(); - __ cmp(lir_cond_equal, cur_value, dirty); - __ branch(lir_cond_equal, T_BYTE, L_already_dirty->label()); - __ move(dirty, card_addr); - __ branch_destination(L_already_dirty->label()); - } else { -#if INCLUDE_ALL_GCS - if (UseConcMarkSweepGC && CMSPrecleaningEnabled) { - __ membar_storestore(); - } -#endif - __ move(dirty, card_addr); - } -#endif -} - - //------------------------field access-------------------------------------- +void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { + assert(x->number_of_arguments() == 4, "wrong type"); + LIRItem obj (x->argument_at(0), this); // object + LIRItem offset(x->argument_at(1), this); // offset of field + LIRItem cmp (x->argument_at(2), this); // value to compare with field + LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp + assert(obj.type()->tag() == objectTag, "invalid type"); + + // In 64bit the type can be long, sparc doesn't have this assert + // assert(offset.type()->tag() == intTag, "invalid type"); + + assert(cmp.type()->tag() == type->tag(), "invalid type"); + assert(val.type()->tag() == type->tag(), "invalid type"); + + LIR_Opr result = access_atomic_cmpxchg_at(IN_HEAP, as_BasicType(type), + obj, offset, cmp, val); + set_result(x, result); +} + // Comment copied form templateTable_i486.cpp // ---------------------------------------------------------------------------- // Volatile variables demand their effects be made known to all CPU's in @@ -1702,7 +1487,6 @@ void LIRGenerator::do_StoreField(StoreField* x) { bool needs_patching = x->needs_patching(); bool is_volatile = x->field()->is_volatile(); BasicType field_type = x->field_type(); - bool is_oop = (field_type == T_ARRAY || field_type == T_OBJECT); CodeEmitInfo* info = NULL; if (needs_patching) { @@ -1717,7 +1501,6 @@ void LIRGenerator::do_StoreField(StoreField* x) { } } - LIRItem object(x->obj(), this); LIRItem value(x->value(), this); @@ -1755,48 +1538,147 @@ void LIRGenerator::do_StoreField(StoreField* x) { __ null_check(object.result(), new CodeEmitInfo(info), /* deoptimize */ needs_patching); } - LIR_Address* address; + DecoratorSet decorators = IN_HEAP; + if (is_volatile) { + decorators |= MO_SEQ_CST; + } if (needs_patching) { - // we need to patch the offset in the instruction so don't allow - // generate_address to try to be smart about emitting the -1. - // Otherwise the patching code won't know how to find the - // instruction to patch. - address = new LIR_Address(object.result(), PATCHED_ADDR, field_type); + decorators |= C1_NEEDS_PATCHING; + } + + access_store_at(decorators, field_type, object, LIR_OprFact::intConst(x->offset()), + value.result(), info != NULL ? new CodeEmitInfo(info) : NULL, info); +} + +void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { + assert(x->is_pinned(),""); + bool needs_range_check = x->compute_needs_range_check(); + bool use_length = x->length() != NULL; + bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; + bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || + !get_jobject_constant(x->value())->is_null_object() || + x->should_profile()); + + LIRItem array(x->array(), this); + LIRItem index(x->index(), this); + LIRItem value(x->value(), this); + LIRItem length(this); + + array.load_item(); + index.load_nonconstant(); + + if (use_length && needs_range_check) { + length.set_instruction(x->length()); + length.load_item(); + + } + if (needs_store_check || x->check_boolean()) { + value.load_item(); } else { - address = generate_address(object.result(), x->offset(), field_type); + value.load_for_store(x->elt_type()); } - if (is_volatile && os::is_MP()) { - __ membar_release(); + set_no_result(x); + + // the CodeEmitInfo must be duplicated for each different + // LIR-instruction because spilling can occur anywhere between two + // instructions and so the debug information must be different + CodeEmitInfo* range_check_info = state_for(x); + CodeEmitInfo* null_check_info = NULL; + if (x->needs_null_check()) { + null_check_info = new CodeEmitInfo(range_check_info); } - if (is_oop) { - // Do the pre-write barrier, if any. - pre_barrier(LIR_OprFact::address(address), - LIR_OprFact::illegalOpr /* pre_val */, - true /* do_load*/, - needs_patching, - (info ? new CodeEmitInfo(info) : NULL)); + if (GenerateRangeChecks && needs_range_check) { + if (use_length) { + __ cmp(lir_cond_belowEqual, length.result(), index.result()); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + } else { + array_range_check(array.result(), index.result(), null_check_info, range_check_info); + // range_check also does the null check + null_check_info = NULL; + } } - bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses; - if (needs_atomic_access && !needs_patching) { - volatile_field_store(value.result(), address, info); + if (GenerateArrayStoreCheck && needs_store_check) { + CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); + array_store_check(value.result(), array.result(), store_check_info, x->profiled_method(), x->profiled_bci()); + } + + DecoratorSet decorators = IN_HEAP | IN_HEAP_ARRAY; + if (x->check_boolean()) { + decorators |= C1_MASK_BOOLEAN; + } + + access_store_at(decorators, x->elt_type(), array, index.result(), value.result(), + NULL, null_check_info); +} + +void LIRGenerator::access_load_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIR_Opr offset, LIR_Opr result, + CodeEmitInfo* patch_info, CodeEmitInfo* load_emit_info) { + decorators |= C1_READ_ACCESS; + LIRAccess access(this, decorators, base, offset, type, patch_info, load_emit_info); + if (access.is_raw()) { + _barrier_set->BarrierSetC1::load_at(access, result); } else { - LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; - __ store(value.result(), address, info, patch_code); - } - - if (is_oop) { - // Store to object so mark the card of the header - post_barrier(object.result(), value.result()); - } - - if (!support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile && os::is_MP()) { - __ membar(); + _barrier_set->load_at(access, result); } } +void LIRGenerator::access_store_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIR_Opr offset, LIR_Opr value, + CodeEmitInfo* patch_info, CodeEmitInfo* store_emit_info) { + decorators |= C1_WRITE_ACCESS; + LIRAccess access(this, decorators, base, offset, type, patch_info, store_emit_info); + if (access.is_raw()) { + _barrier_set->BarrierSetC1::store_at(access, value); + } else { + _barrier_set->store_at(access, value); + } +} + +LIR_Opr LIRGenerator::access_atomic_cmpxchg_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIRItem& offset, LIRItem& cmp_value, LIRItem& new_value) { + // Atomic operations are SEQ_CST by default + decorators |= C1_READ_ACCESS; + decorators |= C1_WRITE_ACCESS; + decorators |= ((decorators & MO_DECORATOR_MASK) != 0) ? MO_SEQ_CST : 0; + LIRAccess access(this, decorators, base, offset, type); + if (access.is_raw()) { + return _barrier_set->BarrierSetC1::atomic_cmpxchg_at(access, cmp_value, new_value); + } else { + return _barrier_set->atomic_cmpxchg_at(access, cmp_value, new_value); + } +} + +LIR_Opr LIRGenerator::access_atomic_xchg_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIRItem& offset, LIRItem& value) { + // Atomic operations are SEQ_CST by default + decorators |= C1_READ_ACCESS; + decorators |= C1_WRITE_ACCESS; + decorators |= ((decorators & MO_DECORATOR_MASK) != 0) ? MO_SEQ_CST : 0; + LIRAccess access(this, decorators, base, offset, type); + if (access.is_raw()) { + return _barrier_set->BarrierSetC1::atomic_xchg_at(access, value); + } else { + return _barrier_set->atomic_xchg_at(access, value); + } +} + +LIR_Opr LIRGenerator::access_atomic_add_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIRItem& offset, LIRItem& value) { + // Atomic operations are SEQ_CST by default + decorators |= C1_READ_ACCESS; + decorators |= C1_WRITE_ACCESS; + decorators |= ((decorators & MO_DECORATOR_MASK) != 0) ? MO_SEQ_CST : 0; + LIRAccess access(this, decorators, base, offset, type); + if (access.is_raw()) { + return _barrier_set->BarrierSetC1::atomic_add_at(access, value); + } else { + return _barrier_set->atomic_add_at(access, value); + } +} void LIRGenerator::do_LoadField(LoadField* x) { bool needs_patching = x->needs_patching(); @@ -1843,33 +1725,18 @@ void LIRGenerator::do_LoadField(LoadField* x) { __ null_check(obj, new CodeEmitInfo(info), /* deoptimize */ needs_patching); } - LIR_Opr reg = rlock_result(x, field_type); - LIR_Address* address; + DecoratorSet decorators = IN_HEAP; + if (is_volatile) { + decorators |= MO_SEQ_CST; + } if (needs_patching) { - // we need to patch the offset in the instruction so don't allow - // generate_address to try to be smart about emitting the -1. - // Otherwise the patching code won't know how to find the - // instruction to patch. - address = new LIR_Address(object.result(), PATCHED_ADDR, field_type); - } else { - address = generate_address(object.result(), x->offset(), field_type); + decorators |= C1_NEEDS_PATCHING; } - if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile && os::is_MP()) { - __ membar(); - } - - bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses; - if (needs_atomic_access && !needs_patching) { - volatile_field_load(address, reg, info); - } else { - LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; - __ load(address, reg, info, patch_code); - } - - if (is_volatile && os::is_MP()) { - __ membar_acquire(); - } + LIR_Opr result = rlock_result(x, field_type); + access_load_at(decorators, field_type, + object, LIR_OprFact::intConst(x->offset()), result, + info ? new CodeEmitInfo(info) : NULL, info); } @@ -1968,9 +1835,6 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) { } } - // emit array address setup early so it schedules better - LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), false); - if (GenerateRangeChecks && needs_range_check) { if (StressLoopInvariantCodeMotion && range_check_info->deoptimize_on_exception()) { __ branch(lir_cond_always, T_ILLEGAL, new RangeCheckStub(range_check_info, index.result())); @@ -1986,7 +1850,12 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) { } } - __ move(array_addr, rlock_result(x, x->elt_type()), null_check_info); + DecoratorSet decorators = IN_HEAP | IN_HEAP_ARRAY; + + LIR_Opr result = rlock_result(x, x->elt_type()); + access_load_at(decorators, x->elt_type(), + array, index.result(), result, + NULL, null_check_info); } @@ -2272,157 +2141,21 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { off.load_item(); src.load_item(); - LIR_Opr value = rlock_result(x, x->basic_type()); + DecoratorSet decorators = IN_HEAP; - if (support_IRIW_for_not_multiple_copy_atomic_cpu && x->is_volatile() && os::is_MP()) { - __ membar(); + if (x->is_volatile()) { + decorators |= MO_SEQ_CST; } - - get_Object_unsafe(value, src.result(), off.result(), type, x->is_volatile()); - -#if INCLUDE_ALL_GCS - // We might be reading the value of the referent field of a - // Reference object in order to attach it back to the live - // object graph. If G1 is enabled then we need to record - // the value that is being returned in an SATB log buffer. - // - // We need to generate code similar to the following... - // - // if (offset == java_lang_ref_Reference::referent_offset) { - // if (src != NULL) { - // if (klass(src)->reference_type() != REF_NONE) { - // pre_barrier(..., value, ...); - // } - // } - // } - - if (UseG1GC && type == T_OBJECT) { - bool gen_pre_barrier = true; // Assume we need to generate pre_barrier. - bool gen_offset_check = true; // Assume we need to generate the offset guard. - bool gen_source_check = true; // Assume we need to check the src object for null. - bool gen_type_check = true; // Assume we need to check the reference_type. - - if (off.is_constant()) { - jlong off_con = (off.type()->is_int() ? - (jlong) off.get_jint_constant() : - off.get_jlong_constant()); - - - if (off_con != (jlong) java_lang_ref_Reference::referent_offset) { - // The constant offset is something other than referent_offset. - // We can skip generating/checking the remaining guards and - // skip generation of the code stub. - gen_pre_barrier = false; - } else { - // The constant offset is the same as referent_offset - - // we do not need to generate a runtime offset check. - gen_offset_check = false; - } - } - - // We don't need to generate stub if the source object is an array - if (gen_pre_barrier && src.type()->is_array()) { - gen_pre_barrier = false; - } - - if (gen_pre_barrier) { - // We still need to continue with the checks. - if (src.is_constant()) { - ciObject* src_con = src.get_jobject_constant(); - guarantee(src_con != NULL, "no source constant"); - - if (src_con->is_null_object()) { - // The constant src object is null - We can skip - // generating the code stub. - gen_pre_barrier = false; - } else { - // Non-null constant source object. We still have to generate - // the slow stub - but we don't need to generate the runtime - // null object check. - gen_source_check = false; - } - } - } - if (gen_pre_barrier && !PatchALot) { - // Can the klass of object be statically determined to be - // a sub-class of Reference? - ciType* type = src.value()->declared_type(); - if ((type != NULL) && type->is_loaded()) { - if (type->is_subtype_of(compilation()->env()->Reference_klass())) { - gen_type_check = false; - } else if (type->is_klass() && - !compilation()->env()->Object_klass()->is_subtype_of(type->as_klass())) { - // Not Reference and not Object klass. - gen_pre_barrier = false; - } - } - } - - if (gen_pre_barrier) { - LabelObj* Lcont = new LabelObj(); - - // We can have generate one runtime check here. Let's start with - // the offset check. - if (gen_offset_check) { - // if (offset != referent_offset) -> continue - // If offset is an int then we can do the comparison with the - // referent_offset constant; otherwise we need to move - // referent_offset into a temporary register and generate - // a reg-reg compare. - - LIR_Opr referent_off; - - if (off.type()->is_int()) { - referent_off = LIR_OprFact::intConst(java_lang_ref_Reference::referent_offset); - } else { - assert(off.type()->is_long(), "what else?"); - referent_off = new_register(T_LONG); - __ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off); - } - __ cmp(lir_cond_notEqual, off.result(), referent_off); - __ branch(lir_cond_notEqual, as_BasicType(off.type()), Lcont->label()); - } - if (gen_source_check) { - // offset is a const and equals referent offset - // if (source == null) -> continue - __ cmp(lir_cond_equal, src.result(), LIR_OprFact::oopConst(NULL)); - __ branch(lir_cond_equal, T_OBJECT, Lcont->label()); - } - LIR_Opr src_klass = new_register(T_OBJECT); - if (gen_type_check) { - // We have determined that offset == referent_offset && src != null. - // if (src->_klass->_reference_type == REF_NONE) -> continue - __ move(new LIR_Address(src.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), src_klass); - LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE); - LIR_Opr reference_type = new_register(T_INT); - __ move(reference_type_addr, reference_type); - __ cmp(lir_cond_equal, reference_type, LIR_OprFact::intConst(REF_NONE)); - __ branch(lir_cond_equal, T_INT, Lcont->label()); - } - { - // We have determined that src->_klass->_reference_type != REF_NONE - // so register the value in the referent field with the pre-barrier. - pre_barrier(LIR_OprFact::illegalOpr /* addr_opr */, - value /* pre_val */, - false /* do_load */, - false /* patch */, - NULL /* info */); - } - __ branch_destination(Lcont->label()); - } - } -#endif // INCLUDE_ALL_GCS - - if (x->is_volatile() && os::is_MP()) __ membar_acquire(); - - /* Normalize boolean value returned by unsafe operation, i.e., value != 0 ? value = true : value false. */ if (type == T_BOOLEAN) { - LabelObj* equalZeroLabel = new LabelObj(); - __ cmp(lir_cond_equal, value, 0); - __ branch(lir_cond_equal, T_BOOLEAN, equalZeroLabel->label()); - __ move(LIR_OprFact::intConst(1), value); - __ branch_destination(equalZeroLabel->label()); + decorators |= C1_MASK_BOOLEAN; } + if (type == T_ARRAY || type == T_OBJECT) { + decorators |= ON_UNKNOWN_OOP_REF; + } + + LIR_Opr result = rlock_result(x, type); + access_load_at(decorators, type, + src, off.result(), result); } @@ -2442,11 +2175,36 @@ void LIRGenerator::do_UnsafePutObject(UnsafePutObject* x) { set_no_result(x); - if (x->is_volatile() && os::is_MP()) __ membar_release(); - put_Object_unsafe(src.result(), off.result(), data.result(), type, x->is_volatile()); - if (!support_IRIW_for_not_multiple_copy_atomic_cpu && x->is_volatile() && os::is_MP()) __ membar(); + DecoratorSet decorators = IN_HEAP; + if (type == T_ARRAY || type == T_OBJECT) { + decorators |= ON_UNKNOWN_OOP_REF; + } + if (x->is_volatile()) { + decorators |= MO_SEQ_CST; + } + access_store_at(decorators, type, src, off.result(), data.result()); } +void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { + BasicType type = x->basic_type(); + LIRItem src(x->object(), this); + LIRItem off(x->offset(), this); + LIRItem value(x->value(), this); + + DecoratorSet decorators = IN_HEAP | MO_SEQ_CST; + + if (type == T_ARRAY || type == T_OBJECT) { + decorators |= ON_UNKNOWN_OOP_REF; + } + + LIR_Opr result; + if (x->is_add()) { + result = access_atomic_add_at(decorators, type, src, off, value); + } else { + result = access_atomic_xchg_at(decorators, type, src, off, value); + } + set_result(x, result); +} void LIRGenerator::do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux) { int lng = x->length(); @@ -3826,25 +3584,30 @@ void LIRGenerator::do_MemBar(MemBar* x) { } } +LIR_Opr LIRGenerator::mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) { + LIR_Opr value_fixed = rlock_byte(T_BYTE); + if (TwoOperandLIRForm) { + __ move(value, value_fixed); + __ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed); + } else { + __ logical_and(value, LIR_OprFact::intConst(1), value_fixed); + } + LIR_Opr klass = new_register(T_METADATA); + __ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info); + null_check_info = NULL; + LIR_Opr layout = new_register(T_INT); + __ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout); + int diffbit = Klass::layout_helper_boolean_diffbit(); + __ logical_and(layout, LIR_OprFact::intConst(diffbit), layout); + __ cmp(lir_cond_notEqual, layout, LIR_OprFact::intConst(0)); + __ cmove(lir_cond_notEqual, value_fixed, value, value_fixed, T_BYTE); + value = value_fixed; + return value; +} + LIR_Opr LIRGenerator::maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) { if (x->check_boolean()) { - LIR_Opr value_fixed = rlock_byte(T_BYTE); - if (TwoOperandLIRForm) { - __ move(value, value_fixed); - __ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed); - } else { - __ logical_and(value, LIR_OprFact::intConst(1), value_fixed); - } - LIR_Opr klass = new_register(T_METADATA); - __ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info); - null_check_info = NULL; - LIR_Opr layout = new_register(T_INT); - __ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout); - int diffbit = Klass::layout_helper_boolean_diffbit(); - __ logical_and(layout, LIR_OprFact::intConst(diffbit), layout); - __ cmp(lir_cond_notEqual, layout, LIR_OprFact::intConst(0)); - __ cmove(lir_cond_notEqual, value_fixed, value, value_fixed, T_BYTE); - value = value_fixed; + value = mask_boolean(array, value, null_check_info); } return value; } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index 22d1235327d..c991c27d8fd 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -25,12 +25,16 @@ #ifndef SHARE_VM_C1_C1_LIRGENERATOR_HPP #define SHARE_VM_C1_C1_LIRGENERATOR_HPP +#include "c1/c1_Decorators.hpp" #include "c1/c1_Instruction.hpp" #include "c1/c1_LIR.hpp" #include "ci/ciMethodData.hpp" +#include "gc/shared/barrierSet.hpp" #include "utilities/macros.hpp" #include "utilities/sizes.hpp" +class BarrierSetC1; + // The classes responsible for code emission and register allocation @@ -165,7 +169,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { Values _instruction_for_operand; BitMap2D _vreg_flags; // flags which can be set on a per-vreg basis LIR_List* _lir; - BarrierSet* _bs; LIRGenerator* gen() { return this; @@ -173,6 +176,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void print_if_not_loaded(const NewInstance* new_instance) PRODUCT_RETURN; + public: #ifdef ASSERT LIR_List* lir(const char * file, int line) const { _lir->set_file_and_line(file, line); @@ -183,6 +187,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { return _lir; } + private: // a simple cache of constants used within a block GrowableArray _constants; LIR_OprList _reg_for_constants; @@ -190,6 +195,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { friend class PhiResolver; + public: // unified bailout support void bailout(const char* msg) const { compilation()->bailout(msg); } bool bailed_out() const { return compilation()->bailed_out(); } @@ -233,14 +239,15 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void move_to_phi(PhiResolver* resolver, Value cur_val, Value sux_val); void move_to_phi(ValueStack* cur_state); - // code emission - void do_ArithmeticOp_Long (ArithmeticOp* x); - void do_ArithmeticOp_Int (ArithmeticOp* x); - void do_ArithmeticOp_FPU (ArithmeticOp* x); - // platform dependent LIR_Opr getThreadPointer(); + private: + // code emission + void do_ArithmeticOp_Long(ArithmeticOp* x); + void do_ArithmeticOp_Int (ArithmeticOp* x); + void do_ArithmeticOp_FPU (ArithmeticOp* x); + void do_RegisterFinalizer(Intrinsic* x); void do_isInstance(Intrinsic* x); void do_isPrimitive(Intrinsic* x); @@ -258,6 +265,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_update_CRC32C(Intrinsic* x); void do_vectorizedMismatch(Intrinsic* x); + public: LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info); LIR_Opr call_runtime(BasicTypeArray* signature, LIR_OprList* args, address entry, ValueType* result_type, CodeEmitInfo* info); @@ -265,27 +273,37 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { LIR_Opr call_runtime(Value arg1, address entry, ValueType* result_type, CodeEmitInfo* info); LIR_Opr call_runtime(Value arg1, Value arg2, address entry, ValueType* result_type, CodeEmitInfo* info); - // GC Barriers + // Access API - // generic interface + private: + BarrierSetC1 *_barrier_set; - void pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, bool do_load, bool patch, CodeEmitInfo* info); - void post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val); + public: + void access_store_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIR_Opr offset, LIR_Opr value, + CodeEmitInfo* patch_info = NULL, CodeEmitInfo* store_emit_info = NULL); + + void access_load_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIR_Opr offset, LIR_Opr result, + CodeEmitInfo* patch_info = NULL, CodeEmitInfo* load_emit_info = NULL); + + LIR_Opr access_atomic_cmpxchg_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIRItem& offset, LIRItem& cmp_value, LIRItem& new_value); + + LIR_Opr access_atomic_xchg_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIRItem& offset, LIRItem& value); + + LIR_Opr access_atomic_add_at(DecoratorSet decorators, BasicType type, + LIRItem& base, LIRItem& offset, LIRItem& value); + + // These need to guarantee JMM volatile semantics are preserved on each platform + // and requires one implementation per architecture. + LIR_Opr atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value); + LIR_Opr atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& new_value); + LIR_Opr atomic_add(BasicType type, LIR_Opr addr, LIRItem& new_value); // specific implementations - // pre barriers - - void G1BarrierSet_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, - bool do_load, bool patch, CodeEmitInfo* info); - - // post barriers - - void G1BarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val); - void CardTableBarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val); -#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER - void CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LIR_Const* card_table_base); -#endif - + void array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci); static LIR_Opr result_register_for(ValueType* type, bool callee = false); @@ -354,7 +372,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { LIR_Address* generate_address(LIR_Opr base, int disp, BasicType type) { return generate_address(base, LIR_OprFact::illegalOpr, 0, disp, type); } - LIR_Address* emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type, bool needs_card_mark); + LIR_Address* emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type); // the helper for generate_address void add_large_constant(LIR_Opr src, int c, LIR_Opr dest); @@ -433,8 +451,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_soft_float_compare(If *x); #endif // __SOFTFP__ - void init(); - SwitchRangeArray* create_lookup_ranges(TableSwitch* x); SwitchRangeArray* create_lookup_ranges(LookupSwitch* x); void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux); @@ -452,6 +468,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void profile_arguments(ProfileCall* x); void profile_parameters(Base* x); void profile_parameters_at_call(ProfileCall* x); + LIR_Opr mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info); LIR_Opr maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info); public: @@ -478,8 +495,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { : _compilation(compilation) , _method(method) , _virtual_register_number(LIR_OprDesc::vreg_base) - , _vreg_flags(num_vreg_flags) { - init(); + , _vreg_flags(num_vreg_flags) + , _barrier_set(BarrierSet::barrier_set()->barrier_set_c1()) { } // for virtual registers, maps them back to Phi's or Local's diff --git a/src/hotspot/share/c1/c1_MacroAssembler.hpp b/src/hotspot/share/c1/c1_MacroAssembler.hpp index a2924c16a7b..c3c4114ee14 100644 --- a/src/hotspot/share/c1/c1_MacroAssembler.hpp +++ b/src/hotspot/share/c1/c1_MacroAssembler.hpp @@ -74,6 +74,9 @@ class StubAssembler: public C1_MacroAssembler { void set_frame_size(int size); void set_num_rt_args(int args); + void save_live_registers(); + void restore_live_registers_without_return(); + // accessors const char* name() const { return _name; } bool must_gc_arguments() const { return _must_gc_arguments; } @@ -86,6 +89,9 @@ class StubAssembler: public C1_MacroAssembler { int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1); int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2); int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3); + + void prologue(const char* name, bool must_gc_arguments); + void epilogue(); }; #endif // SHARE_VM_C1_C1_MACROASSEMBLER_HPP diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index d00a93c4940..848e5bef354 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -39,6 +39,7 @@ #include "code/vtableStubs.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" +#include "gc/shared/c1/barrierSetC1.hpp" #include "gc/shared/collectedHeap.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/interpreter.hpp" @@ -178,9 +179,17 @@ static void deopt_caller() { } } +class StubIDStubAssemblerCodeGenClosure: public StubAssemblerCodeGenClosure { + private: + Runtime1::StubID _id; + public: + StubIDStubAssemblerCodeGenClosure(Runtime1::StubID id) : _id(id) {} + virtual OopMapSet* generate_code(StubAssembler* sasm) { + return Runtime1::generate_code_for(_id, sasm); + } +}; -void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); +CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, int stub_id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure* cl) { ResourceMark rm; // create code buffer for code storage CodeBuffer code(buffer_blob); @@ -192,33 +201,12 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { Compilation::setup_code_buffer(&code, 0); // create assembler for code generation - StubAssembler* sasm = new StubAssembler(&code, name_for(id), id); + StubAssembler* sasm = new StubAssembler(&code, name, stub_id); // generate code for runtime stub - oop_maps = generate_code_for(id, sasm); + oop_maps = cl->generate_code(sasm); assert(oop_maps == NULL || sasm->frame_size() != no_frame_size, "if stub has an oop map it must have a valid frame size"); - -#ifdef ASSERT - // Make sure that stubs that need oopmaps have them - switch (id) { - // These stubs don't need to have an oopmap - case dtrace_object_alloc_id: - case g1_pre_barrier_slow_id: - case g1_post_barrier_slow_id: - case slow_subtype_check_id: - case fpu2long_stub_id: - case unwind_exception_id: - case counter_overflow_id: -#if defined(SPARC) || defined(PPC32) - case handle_exception_nofpu_id: // Unused on sparc -#endif - break; - - // All other stubs should have oopmaps - default: - assert(oop_maps != NULL, "must have an oopmap"); - } -#endif + assert(!expect_oop_map || oop_maps != NULL, "must have an oopmap"); // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned) sasm->align(BytesPerWord); @@ -228,17 +216,42 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { frame_size = sasm->frame_size(); must_gc_arguments = sasm->must_gc_arguments(); // create blob - distinguish a few special cases - CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id), + CodeBlob* blob = RuntimeStub::new_runtime_stub(name, &code, CodeOffsets::frame_never_safe, frame_size, oop_maps, must_gc_arguments); - // install blob assert(blob != NULL, "blob must exist"); - _blobs[id] = blob; + return blob; } +void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { + assert(0 <= id && id < number_of_ids, "illegal stub id"); + bool expect_oop_map = true; +#ifdef ASSERT + // Make sure that stubs that need oopmaps have them + switch (id) { + // These stubs don't need to have an oopmap + case dtrace_object_alloc_id: + case slow_subtype_check_id: + case fpu2long_stub_id: + case unwind_exception_id: + case counter_overflow_id: +#if defined(SPARC) || defined(PPC32) + case handle_exception_nofpu_id: // Unused on sparc +#endif + expect_oop_map = false; + break; + default: + break; + } +#endif + StubIDStubAssemblerCodeGenClosure cl(id); + CodeBlob* blob = generate_blob(buffer_blob, id, name_for(id), expect_oop_map, &cl); + // install blob + _blobs[id] = blob; +} void Runtime1::initialize(BufferBlob* blob) { // platform-dependent initialization @@ -257,9 +270,10 @@ void Runtime1::initialize(BufferBlob* blob) { } } #endif + BarrierSetC1* bs = BarrierSet::barrier_set()->barrier_set_c1(); + bs->generate_c1_runtime_stubs(blob); } - CodeBlob* Runtime1::blob_for(StubID id) { assert(0 <= id && id < number_of_ids, "illegal stub id"); return _blobs[id]; diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp index 88ec4267c8c..b728327bee2 100644 --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,8 +68,6 @@ class StubAssembler; stub(load_klass_patching) \ stub(load_mirror_patching) \ stub(load_appendix_patching) \ - stub(g1_pre_barrier_slow) \ - stub(g1_post_barrier_slow) \ stub(fpu2long_stub) \ stub(counter_overflow) \ stub(predicate_failed_trap) \ @@ -80,6 +78,11 @@ class StubAssembler; #define STUB_NAME(x) #x " Runtime1 stub", #define LAST_STUB_NAME(x) #x " Runtime1 stub" +class StubAssemblerCodeGenClosure: public Closure { + public: + virtual OopMapSet* generate_code(StubAssembler* sasm) = 0; +}; + class Runtime1: public AllStatic { friend class VMStructs; friend class ArrayCopyStub; @@ -121,8 +124,11 @@ class Runtime1: public AllStatic { static const char* _blob_names[]; // stub generation + public: + static CodeBlob* generate_blob(BufferBlob* buffer_blob, int stub_id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure *cl); static void generate_blob_for(BufferBlob* blob, StubID id); static OopMapSet* generate_code_for(StubID id, StubAssembler* sasm); + private: static OopMapSet* generate_exception_throw(StubAssembler* sasm, address target, bool has_argument); static OopMapSet* generate_handle_exception(StubID id, StubAssembler* sasm); static void generate_unwind_exception(StubAssembler *sasm); diff --git a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp new file mode 100644 index 00000000000..62e765f7b6c --- /dev/null +++ b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#include "gc/g1/g1BarrierSet.hpp" +#include "gc/g1/g1BarrierSetAssembler.hpp" +#include "gc/g1/g1ThreadLocalData.hpp" +#include "gc/g1/heapRegion.hpp" +#include "utilities/macros.hpp" + +#ifdef ASSERT +#define __ gen->lir(__FILE__, __LINE__)-> +#else +#define __ gen->lir()-> +#endif + +void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { + G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); + bs->gen_pre_barrier_stub(ce, this); +} + +void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { + G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); + bs->gen_post_barrier_stub(ce, this); +} + +void G1BarrierSetC1::pre_barrier(LIRAccess& access, LIR_Opr addr_opr, + LIR_Opr pre_val, CodeEmitInfo* info) { + LIRGenerator* gen = access.gen(); + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + bool in_conc_root = (decorators & IN_CONCURRENT_ROOT) != 0; + if (!in_heap && !in_conc_root) { + return; + } + + // First we test whether marking is in progress. + BasicType flag_type; + bool patch = (decorators & C1_NEEDS_PATCHING) != 0; + bool do_load = pre_val == LIR_OprFact::illegalOpr; + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + flag_type = T_INT; + } else { + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, + "Assumption"); + // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM, + // need to use unsigned instructions to use the large offset to load the satb_mark_queue. + flag_type = T_BOOLEAN; + } + LIR_Opr thrd = gen->getThreadPointer(); + LIR_Address* mark_active_flag_addr = + new LIR_Address(thrd, + in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), + flag_type); + // Read the marking-in-progress flag. + LIR_Opr flag_val = gen->new_register(T_INT); + __ load(mark_active_flag_addr, flag_val); + __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); + + LIR_PatchCode pre_val_patch_code = lir_patch_none; + + CodeStub* slow; + + if (do_load) { + assert(pre_val == LIR_OprFact::illegalOpr, "sanity"); + assert(addr_opr != LIR_OprFact::illegalOpr, "sanity"); + + if (patch) + pre_val_patch_code = lir_patch_normal; + + pre_val = gen->new_register(T_OBJECT); + + if (!addr_opr->is_address()) { + assert(addr_opr->is_register(), "must be"); + addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT)); + } + slow = new G1PreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info); + } else { + assert(addr_opr == LIR_OprFact::illegalOpr, "sanity"); + assert(pre_val->is_register(), "must be"); + assert(pre_val->type() == T_OBJECT, "must be an object"); + assert(info == NULL, "sanity"); + + slow = new G1PreBarrierStub(pre_val); + } + + __ branch(lir_cond_notEqual, T_INT, slow); + __ branch_destination(slow->continuation()); +} + +void G1BarrierSetC1::post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val) { + LIRGenerator* gen = access.gen(); + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + if (!in_heap) { + return; + } + + // If the "new_val" is a constant NULL, no barrier is necessary. + if (new_val->is_constant() && + new_val->as_constant_ptr()->as_jobject() == NULL) return; + + if (!new_val->is_register()) { + LIR_Opr new_val_reg = gen->new_register(T_OBJECT); + if (new_val->is_constant()) { + __ move(new_val, new_val_reg); + } else { + __ leal(new_val, new_val_reg); + } + new_val = new_val_reg; + } + assert(new_val->is_register(), "must be a register at this point"); + + if (addr->is_address()) { + LIR_Address* address = addr->as_address_ptr(); + LIR_Opr ptr = gen->new_pointer_register(); + if (!address->index()->is_valid() && address->disp() == 0) { + __ move(address->base(), ptr); + } else { + assert(address->disp() != max_jint, "lea doesn't support patched addresses!"); + __ leal(addr, ptr); + } + addr = ptr; + } + assert(addr->is_register(), "must be a register at this point"); + + LIR_Opr xor_res = gen->new_pointer_register(); + LIR_Opr xor_shift_res = gen->new_pointer_register(); + if (TwoOperandLIRForm) { + __ move(addr, xor_res); + __ logical_xor(xor_res, new_val, xor_res); + __ move(xor_res, xor_shift_res); + __ unsigned_shift_right(xor_shift_res, + LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes), + xor_shift_res, + LIR_OprDesc::illegalOpr()); + } else { + __ logical_xor(addr, new_val, xor_res); + __ unsigned_shift_right(xor_res, + LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes), + xor_shift_res, + LIR_OprDesc::illegalOpr()); + } + + if (!new_val->is_register()) { + LIR_Opr new_val_reg = gen->new_register(T_OBJECT); + __ leal(new_val, new_val_reg); + new_val = new_val_reg; + } + assert(new_val->is_register(), "must be a register at this point"); + + __ cmp(lir_cond_notEqual, xor_shift_res, LIR_OprFact::intptrConst(NULL_WORD)); + + CodeStub* slow = new G1PostBarrierStub(addr, new_val); + __ branch(lir_cond_notEqual, LP64_ONLY(T_LONG) NOT_LP64(T_INT), slow); + __ branch_destination(slow->continuation()); +} + +void G1BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { + DecoratorSet decorators = access.decorators(); + bool is_weak = (decorators & ON_WEAK_OOP_REF) != 0; + bool is_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; + bool is_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; + LIRGenerator *gen = access.gen(); + + BarrierSetC1::load_at_resolved(access, result); + + if (access.is_oop() && (is_weak || is_phantom || is_anonymous)) { + // Register the value in the referent field with the pre-barrier + LabelObj *Lcont_anonymous; + if (is_anonymous) { + Lcont_anonymous = new LabelObj(); + generate_referent_check(access, Lcont_anonymous); + } + pre_barrier(access, LIR_OprFact::illegalOpr /* addr_opr */, + result /* pre_val */, access.patch_emit_info() /* info */); + if (is_anonymous) { + __ branch_destination(Lcont_anonymous->label()); + } + } +} + +class C1G1PreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { + virtual OopMapSet* generate_code(StubAssembler* sasm) { + G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); + bs->generate_c1_pre_barrier_runtime_stub(sasm); + return NULL; + } +}; + +class C1G1PostBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { + virtual OopMapSet* generate_code(StubAssembler* sasm) { + G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); + bs->generate_c1_post_barrier_runtime_stub(sasm); + return NULL; + } +}; + +void G1BarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) { + C1G1PreBarrierCodeGenClosure pre_code_gen_cl; + C1G1PostBarrierCodeGenClosure post_code_gen_cl; + _pre_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1, "g1_pre_barrier_slow", + false, &pre_code_gen_cl); + _post_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1, "g1_post_barrier_slow", + false, &post_code_gen_cl); +} diff --git a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.hpp b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.hpp new file mode 100644 index 00000000000..6d4185096f1 --- /dev/null +++ b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.hpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_C1_G1BARRIERSETC1_HPP +#define SHARE_GC_G1_C1_G1BARRIERSETC1_HPP + +#include "c1/c1_CodeStubs.hpp" +#include "gc/shared/c1/modRefBarrierSetC1.hpp" + +class G1PreBarrierStub: public CodeStub { + friend class G1BarrierSetC1; + private: + bool _do_load; + LIR_Opr _addr; + LIR_Opr _pre_val; + LIR_PatchCode _patch_code; + CodeEmitInfo* _info; + + public: + // Version that _does_ generate a load of the previous value from addr. + // addr (the address of the field to be read) must be a LIR_Address + // pre_val (a temporary register) must be a register; + G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) : + _addr(addr), _pre_val(pre_val), _do_load(true), + _patch_code(patch_code), _info(info) + { + assert(_pre_val->is_register(), "should be temporary register"); + assert(_addr->is_address(), "should be the address of the field"); + } + + // Version that _does not_ generate load of the previous value; the + // previous value is assumed to have already been loaded into pre_val. + G1PreBarrierStub(LIR_Opr pre_val) : + _addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false), + _patch_code(lir_patch_none), _info(NULL) + { + assert(_pre_val->is_register(), "should be a register"); + } + + LIR_Opr addr() const { return _addr; } + LIR_Opr pre_val() const { return _pre_val; } + LIR_PatchCode patch_code() const { return _patch_code; } + CodeEmitInfo* info() const { return _info; } + bool do_load() const { return _do_load; } + + virtual void emit_code(LIR_Assembler* e); + virtual void visit(LIR_OpVisitState* visitor) { + if (_do_load) { + // don't pass in the code emit info since it's processed in the fast + // path + if (_info != NULL) + visitor->do_slow_case(_info); + else + visitor->do_slow_case(); + + visitor->do_input(_addr); + visitor->do_temp(_pre_val); + } else { + visitor->do_slow_case(); + visitor->do_input(_pre_val); + } + } +#ifndef PRODUCT + virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); } +#endif // PRODUCT +}; + +class G1PostBarrierStub: public CodeStub { + friend class G1BarrierSetC1; + private: + LIR_Opr _addr; + LIR_Opr _new_val; + + public: + // addr (the address of the object head) and new_val must be registers. + G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { } + + LIR_Opr addr() const { return _addr; } + LIR_Opr new_val() const { return _new_val; } + + virtual void emit_code(LIR_Assembler* e); + virtual void visit(LIR_OpVisitState* visitor) { + // don't pass in the code emit info since it's processed in the fast path + visitor->do_slow_case(); + visitor->do_input(_addr); + visitor->do_input(_new_val); + } +#ifndef PRODUCT + virtual void print_name(outputStream* out) const { out->print("G1PostBarrierStub"); } +#endif // PRODUCT +}; + +class CodeBlob; + +class G1BarrierSetC1 : public ModRefBarrierSetC1 { + protected: + CodeBlob* _pre_barrier_c1_runtime_code_blob; + CodeBlob* _post_barrier_c1_runtime_code_blob; + + virtual void pre_barrier(LIRAccess& access, LIR_Opr addr_opr, + LIR_Opr pre_val, CodeEmitInfo* info); + virtual void post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val); + + virtual void load_at_resolved(LIRAccess& access, LIR_Opr result); + + public: + G1BarrierSetC1() + : _pre_barrier_c1_runtime_code_blob(NULL), + _post_barrier_c1_runtime_code_blob(NULL) {} + + CodeBlob* pre_barrier_c1_runtime_code_blob() { return _pre_barrier_c1_runtime_code_blob; } + CodeBlob* post_barrier_c1_runtime_code_blob() { return _post_barrier_c1_runtime_code_blob; } + + virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob); +}; + +#endif // SHARE_GC_G1_C1_G1BARRIERSETC1_HPP diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp index ef3419d36a7..f5b90a4e050 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp @@ -37,12 +37,18 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif + +class G1BarrierSetC1; SATBMarkQueueSet G1BarrierSet::_satb_mark_queue_set; DirtyCardQueueSet G1BarrierSet::_dirty_card_queue_set; G1BarrierSet::G1BarrierSet(G1CardTable* card_table) : CardTableBarrierSet(make_barrier_set_assembler(), + make_barrier_set_c1(), card_table, BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)) {} diff --git a/src/hotspot/share/gc/shared/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp index 1ee37cd0f58..3972ddc0c82 100644 --- a/src/hotspot/share/gc/shared/barrierSet.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.hpp @@ -33,8 +33,9 @@ #include "utilities/fakeRttiSupport.hpp" #include "utilities/macros.hpp" -class JavaThread; class BarrierSetAssembler; +class BarrierSetC1; +class JavaThread; // This class provides the interface between a barrier implementation and // the rest of the system. @@ -68,6 +69,7 @@ protected: private: FakeRtti _fake_rtti; BarrierSetAssembler* _barrier_set_assembler; + BarrierSetC1* _barrier_set_c1; public: // Metafunction mapping a class derived from BarrierSet to the @@ -88,9 +90,12 @@ public: // End of fake RTTI support. protected: - BarrierSet(BarrierSetAssembler* barrier_set_assembler, const FakeRtti& fake_rtti) : + BarrierSet(BarrierSetAssembler* barrier_set_assembler, + BarrierSetC1* barrier_set_c1, + const FakeRtti& fake_rtti) : _fake_rtti(fake_rtti), - _barrier_set_assembler(barrier_set_assembler) { } + _barrier_set_assembler(barrier_set_assembler), + _barrier_set_c1(barrier_set_c1) {} ~BarrierSet() { } template @@ -98,6 +103,11 @@ protected: return NOT_ZERO(new BarrierSetAssemblerT()) ZERO_ONLY(NULL); } + template + BarrierSetC1* make_barrier_set_c1() { + return COMPILER1_PRESENT(new BarrierSetC1T()) NOT_COMPILER1(NULL); + } + public: // Support for optimizing compilers to call the barrier set on slow path allocations // that did not enter a TLAB. Used for e.g. ReduceInitialCardMarks. @@ -123,6 +133,11 @@ public: return _barrier_set_assembler; } + BarrierSetC1* barrier_set_c1() { + assert(_barrier_set_c1 != NULL, "should be set"); + return _barrier_set_c1; + } + // The AccessBarrier of a BarrierSet subclass is called by the Access API // (cf. oops/access.hpp) to perform decorated accesses. GC implementations // may override these default access operations by declaring an diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp new file mode 100644 index 00000000000..4f23e01fd09 --- /dev/null +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Defs.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "gc/shared/c1/barrierSetC1.hpp" +#include "utilities/macros.hpp" + +#ifndef PATCHED_ADDR +#define PATCHED_ADDR (max_jint) +#endif + +#ifdef ASSERT +#define __ gen->lir(__FILE__, __LINE__)-> +#else +#define __ gen->lir()-> +#endif + +LIR_Opr BarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { + DecoratorSet decorators = access.decorators(); + bool on_array = (decorators & IN_HEAP_ARRAY) != 0; + bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; + + LIRItem& base = access.base().item(); + LIR_Opr offset = access.offset().opr(); + LIRGenerator *gen = access.gen(); + + LIR_Opr addr_opr; + if (on_array) { + addr_opr = LIR_OprFact::address(gen->emit_array_address(base.result(), offset, access.type())); + } else if (needs_patching) { + // we need to patch the offset in the instruction so don't allow + // generate_address to try to be smart about emitting the -1. + // Otherwise the patching code won't know how to find the + // instruction to patch. + addr_opr = LIR_OprFact::address(new LIR_Address(base.result(), PATCHED_ADDR, access.type())); + } else { + addr_opr = LIR_OprFact::address(gen->generate_address(base.result(), offset, 0, 0, access.type())); + } + + if (resolve_in_register) { + LIR_Opr resolved_addr = gen->new_pointer_register(); + __ leal(addr_opr, resolved_addr); + resolved_addr = LIR_OprFact::address(new LIR_Address(resolved_addr, access.type())); + return resolved_addr; + } else { + return addr_opr; + } +} + +void BarrierSetC1::store_at(LIRAccess& access, LIR_Opr value) { + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + assert(in_heap, "not supported yet"); + + LIR_Opr resolved = resolve_address(access, false); + access.set_resolved_addr(resolved); + store_at_resolved(access, value); +} + +void BarrierSetC1::load_at(LIRAccess& access, LIR_Opr result) { + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + assert(in_heap, "not supported yet"); + + LIR_Opr resolved = resolve_address(access, false); + access.set_resolved_addr(resolved); + load_at_resolved(access, result); +} + +LIR_Opr BarrierSetC1::atomic_cmpxchg_at(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + assert(in_heap, "not supported yet"); + + access.load_address(); + + LIR_Opr resolved = resolve_address(access, true); + access.set_resolved_addr(resolved); + return atomic_cmpxchg_at_resolved(access, cmp_value, new_value); +} + +LIR_Opr BarrierSetC1::atomic_xchg_at(LIRAccess& access, LIRItem& value) { + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + assert(in_heap, "not supported yet"); + + access.load_address(); + + LIR_Opr resolved = resolve_address(access, true); + access.set_resolved_addr(resolved); + return atomic_xchg_at_resolved(access, value); +} + +LIR_Opr BarrierSetC1::atomic_add_at(LIRAccess& access, LIRItem& value) { + DecoratorSet decorators = access.decorators(); + bool in_heap = (decorators & IN_HEAP) != 0; + assert(in_heap, "not supported yet"); + + access.load_address(); + + LIR_Opr resolved = resolve_address(access, true); + access.set_resolved_addr(resolved); + return atomic_add_at_resolved(access, value); +} + +void BarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { + DecoratorSet decorators = access.decorators(); + bool is_volatile = (((decorators & MO_SEQ_CST) != 0) || AlwaysAtomicAccesses) && os::is_MP(); + bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; + bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; + LIRGenerator* gen = access.gen(); + + if (mask_boolean) { + value = gen->mask_boolean(access.base().opr(), value, access.access_emit_info()); + } + + if (is_volatile && os::is_MP()) { + __ membar_release(); + } + + LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; + if (is_volatile && !needs_patching) { + gen->volatile_field_store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info()); + } else { + __ store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info(), patch_code); + } + + if (is_volatile && !support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } +} + +void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { + LIRGenerator *gen = access.gen(); + DecoratorSet decorators = access.decorators(); + bool is_volatile = (((decorators & MO_SEQ_CST) != 0) || AlwaysAtomicAccesses) && os::is_MP(); + bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; + bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; + + if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile) { + __ membar(); + } + + LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; + if (is_volatile && !needs_patching) { + gen->volatile_field_load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info()); + } else { + __ load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info(), patch_code); + } + + if (is_volatile && os::is_MP()) { + __ membar_acquire(); + } + + /* Normalize boolean value returned by unsafe operation, i.e., value != 0 ? value = true : value false. */ + if (mask_boolean) { + LabelObj* equalZeroLabel = new LabelObj(); + __ cmp(lir_cond_equal, result, 0); + __ branch(lir_cond_equal, T_BOOLEAN, equalZeroLabel->label()); + __ move(LIR_OprFact::intConst(1), result); + __ branch_destination(equalZeroLabel->label()); + } +} + +LIR_Opr BarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { + LIRGenerator *gen = access.gen(); + return gen->atomic_cmpxchg(access.type(), access.resolved_addr(), cmp_value, new_value); +} + +LIR_Opr BarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) { + LIRGenerator *gen = access.gen(); + return gen->atomic_xchg(access.type(), access.resolved_addr(), value); +} + +LIR_Opr BarrierSetC1::atomic_add_at_resolved(LIRAccess& access, LIRItem& value) { + LIRGenerator *gen = access.gen(); + return gen->atomic_add(access.type(), access.resolved_addr(), value); +} + +void BarrierSetC1::generate_referent_check(LIRAccess& access, LabelObj* cont) { + // We might be reading the value of the referent field of a + // Reference object in order to attach it back to the live + // object graph. If G1 is enabled then we need to record + // the value that is being returned in an SATB log buffer. + // + // We need to generate code similar to the following... + // + // if (offset == java_lang_ref_Reference::referent_offset) { + // if (src != NULL) { + // if (klass(src)->reference_type() != REF_NONE) { + // pre_barrier(..., value, ...); + // } + // } + // } + + bool gen_pre_barrier = true; // Assume we need to generate pre_barrier. + bool gen_offset_check = true; // Assume we need to generate the offset guard. + bool gen_source_check = true; // Assume we need to check the src object for null. + bool gen_type_check = true; // Assume we need to check the reference_type. + + LIRGenerator *gen = access.gen(); + + LIRItem& base = access.base().item(); + LIR_Opr offset = access.offset().opr(); + + if (offset->is_constant()) { + LIR_Const* constant = offset->as_constant_ptr(); + jlong off_con = (constant->type() == T_INT ? + (jlong)constant->as_jint() : + constant->as_jlong()); + + + if (off_con != (jlong) java_lang_ref_Reference::referent_offset) { + // The constant offset is something other than referent_offset. + // We can skip generating/checking the remaining guards and + // skip generation of the code stub. + gen_pre_barrier = false; + } else { + // The constant offset is the same as referent_offset - + // we do not need to generate a runtime offset check. + gen_offset_check = false; + } + } + + // We don't need to generate stub if the source object is an array + if (gen_pre_barrier && base.type()->is_array()) { + gen_pre_barrier = false; + } + + if (gen_pre_barrier) { + // We still need to continue with the checks. + if (base.is_constant()) { + ciObject* src_con = base.get_jobject_constant(); + guarantee(src_con != NULL, "no source constant"); + + if (src_con->is_null_object()) { + // The constant src object is null - We can skip + // generating the code stub. + gen_pre_barrier = false; + } else { + // Non-null constant source object. We still have to generate + // the slow stub - but we don't need to generate the runtime + // null object check. + gen_source_check = false; + } + } + } + if (gen_pre_barrier && !PatchALot) { + // Can the klass of object be statically determined to be + // a sub-class of Reference? + ciType* type = base.value()->declared_type(); + if ((type != NULL) && type->is_loaded()) { + if (type->is_subtype_of(gen->compilation()->env()->Reference_klass())) { + gen_type_check = false; + } else if (type->is_klass() && + !gen->compilation()->env()->Object_klass()->is_subtype_of(type->as_klass())) { + // Not Reference and not Object klass. + gen_pre_barrier = false; + } + } + } + + if (gen_pre_barrier) { + // We can have generate one runtime check here. Let's start with + // the offset check. + if (gen_offset_check) { + // if (offset != referent_offset) -> continue + // If offset is an int then we can do the comparison with the + // referent_offset constant; otherwise we need to move + // referent_offset into a temporary register and generate + // a reg-reg compare. + + LIR_Opr referent_off; + + if (offset->type() == T_INT) { + referent_off = LIR_OprFact::intConst(java_lang_ref_Reference::referent_offset); + } else { + assert(offset->type() == T_LONG, "what else?"); + referent_off = gen->new_register(T_LONG); + __ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off); + } + __ cmp(lir_cond_notEqual, offset, referent_off); + __ branch(lir_cond_notEqual, offset->type(), cont->label()); + } + if (gen_source_check) { + // offset is a const and equals referent offset + // if (source == null) -> continue + __ cmp(lir_cond_equal, base.result(), LIR_OprFact::oopConst(NULL)); + __ branch(lir_cond_equal, T_OBJECT, cont->label()); + } + LIR_Opr src_klass = gen->new_register(T_OBJECT); + if (gen_type_check) { + // We have determined that offset == referent_offset && src != null. + // if (src->_klass->_reference_type == REF_NONE) -> continue + __ move(new LIR_Address(base.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), src_klass); + LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE); + LIR_Opr reference_type = gen->new_register(T_INT); + __ move(reference_type_addr, reference_type); + __ cmp(lir_cond_equal, reference_type, LIR_OprFact::intConst(REF_NONE)); + __ branch(lir_cond_equal, T_INT, cont->label()); + } + } +} diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp new file mode 100644 index 00000000000..d1522c1cef7 --- /dev/null +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_C1_BARRIERSETC1_HPP +#define SHARE_GC_SHARED_C1_BARRIERSETC1_HPP + +#include "c1/c1_Decorators.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "c1/c1_Instruction.hpp" +#include "c1/c1_LIR.hpp" +#include "memory/allocation.hpp" + +class LIRGenerator; +class LIRItem; + +// The LIRAddressOpr comprises either a LIRItem or a LIR_Opr to describe elements +// of an access in the C1 Access API. Both of them allow asking for the opr() which +// will correspond to either _item.result() or _opr if there is no _item. +class LIRAddressOpr: public StackObj { + LIRItem* _item; + LIR_Opr _opr; +public: + LIRAddressOpr(LIRItem& item) : _item(&item), _opr(NULL) {} + LIRAddressOpr(LIR_Opr opr) : _item(NULL), _opr(opr) {} + LIRAddressOpr(const LIRAddressOpr& other) : _item(other._item), _opr(other._opr) {} + + LIRItem& item() const { + assert(_item != NULL, "sanity"); + return *_item; + } + + LIR_Opr opr() const { + if (_item == NULL) { + return _opr; + } else { + return _item->result(); + } + } +}; + +// The LIRAccess class wraps shared context parameters required for performing +// the right access in C1. This includes the address of the offset and the decorators. +class LIRAccess: public StackObj { + LIRGenerator* _gen; + DecoratorSet _decorators; + LIRAddressOpr _base; + LIRAddressOpr _offset; + BasicType _type; + LIR_Opr _resolved_addr; + CodeEmitInfo* _patch_emit_info; + CodeEmitInfo* _access_emit_info; + +public: + LIRAccess(LIRGenerator* gen, DecoratorSet decorators, + LIRAddressOpr base, LIRAddressOpr offset, BasicType type, + CodeEmitInfo* patch_emit_info = NULL, CodeEmitInfo* access_emit_info = NULL) : + _gen(gen), + _decorators(AccessInternal::decorator_fixup(decorators)), + _base(base), + _offset(offset), + _type(type), + _resolved_addr(NULL), + _patch_emit_info(patch_emit_info), + _access_emit_info(access_emit_info) {} + + void load_base() { _base.item().load_item(); } + void load_offset() { _offset.item().load_nonconstant(); } + + void load_address() { + load_base(); + load_offset(); + } + + LIRGenerator* gen() const { return _gen; } + CodeEmitInfo*& patch_emit_info() { return _patch_emit_info; } + CodeEmitInfo*& access_emit_info() { return _access_emit_info; } + LIRAddressOpr& base() { return _base; } + LIRAddressOpr& offset() { return _offset; } + BasicType type() const { return _type; } + LIR_Opr resolved_addr() const { return _resolved_addr; } + void set_resolved_addr(LIR_Opr addr) { _resolved_addr = addr; } + bool is_oop() const { return _type == T_ARRAY || _type == T_OBJECT; } + DecoratorSet decorators() const { return _decorators; } + bool is_raw() const { return (_decorators & AS_RAW) != 0; } +}; + +// The BarrierSetC1 class is the main entry point for the GC backend of the Access API in C1. +// It is called by the LIRGenerator::access_* functions, which is the main entry poing for +// access calls in C1. + +class BarrierSetC1: public CHeapObj { +protected: + virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register); + + virtual void generate_referent_check(LIRAccess& access, LabelObj* cont); + + // Accesses with resolved address + virtual void store_at_resolved(LIRAccess& access, LIR_Opr value); + virtual void load_at_resolved(LIRAccess& access, LIR_Opr result); + + virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value); + + virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value); + virtual LIR_Opr atomic_add_at_resolved(LIRAccess& access, LIRItem& value); + +public: + virtual void store_at(LIRAccess& access, LIR_Opr value); + virtual void load_at(LIRAccess& access, LIR_Opr result); + + virtual LIR_Opr atomic_cmpxchg_at(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value); + + virtual LIR_Opr atomic_xchg_at(LIRAccess& access, LIRItem& value); + virtual LIR_Opr atomic_add_at(LIRAccess& access, LIRItem& value); + + virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob) {} +}; + +#endif // SHARE_GC_SHARED_C1_BARRIERSETC1_HPP diff --git a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp new file mode 100644 index 00000000000..f63638283ce --- /dev/null +++ b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "gc/shared/c1/cardTableBarrierSetC1.hpp" +#include "gc/shared/cardTableBarrierSet.hpp" +#include "utilities/macros.hpp" + +#ifdef ASSERT +#define __ gen->lir(__FILE__, __LINE__)-> +#else +#define __ gen->lir()-> +#endif + +void CardTableBarrierSetC1::post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val) { + DecoratorSet decorators = access.decorators(); + LIRGenerator* gen = access.gen(); + bool in_heap = (decorators & IN_HEAP) != 0; + if (!in_heap) { + return; + } + + BarrierSet* bs = BarrierSet::barrier_set(); + CardTableBarrierSet* ctbs = barrier_set_cast(bs); + CardTable* ct = ctbs->card_table(); + assert(sizeof(*(ct->byte_map_base())) == sizeof(jbyte), "adjust this code"); + LIR_Const* card_table_base = new LIR_Const(ct->byte_map_base()); + if (addr->is_address()) { + LIR_Address* address = addr->as_address_ptr(); + // ptr cannot be an object because we use this barrier for array card marks + // and addr can point in the middle of an array. + LIR_Opr ptr = gen->new_pointer_register(); + if (!address->index()->is_valid() && address->disp() == 0) { + __ move(address->base(), ptr); + } else { + assert(address->disp() != max_jint, "lea doesn't support patched addresses!"); + __ leal(addr, ptr); + } + addr = ptr; + } + assert(addr->is_register(), "must be a register at this point"); + +#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER + gen->CardTableBarrierSet_post_barrier_helper(addr, card_table_base); +#else + LIR_Opr tmp = gen->new_pointer_register(); + if (TwoOperandLIRForm) { + __ move(addr, tmp); + __ unsigned_shift_right(tmp, CardTable::card_shift, tmp); + } else { + __ unsigned_shift_right(addr, CardTable::card_shift, tmp); + } + + LIR_Address* card_addr; + if (gen->can_inline_as_constant(card_table_base)) { + card_addr = new LIR_Address(tmp, card_table_base->as_jint(), T_BYTE); + } else { + card_addr = new LIR_Address(tmp, gen->load_constant(card_table_base), T_BYTE); + } + + LIR_Opr dirty = LIR_OprFact::intConst(CardTable::dirty_card_val()); + if (UseCondCardMark) { + LIR_Opr cur_value = gen->new_register(T_INT); + if (ct->scanned_concurrently()) { + __ membar_storeload(); + } + __ move(card_addr, cur_value); + + LabelObj* L_already_dirty = new LabelObj(); + __ cmp(lir_cond_equal, cur_value, dirty); + __ branch(lir_cond_equal, T_BYTE, L_already_dirty->label()); + __ move(dirty, card_addr); + __ branch_destination(L_already_dirty->label()); + } else { + if (ct->scanned_concurrently()) { + __ membar_storestore(); + } + __ move(dirty, card_addr); + } +#endif +} diff --git a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.hpp b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.hpp new file mode 100644 index 00000000000..e213ead0ab6 --- /dev/null +++ b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_GC_SHARED_C1_CARDTABLEBARRIERSETC1_HPP +#define SHARE_GC_SHARED_C1_CARDTABLEBARRIERSETC1_HPP + +#include "gc/shared/c1/modRefBarrierSetC1.hpp" + +class CardTableBarrierSetC1 : public ModRefBarrierSetC1 { +protected: + virtual void post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val); +}; + +#endif // SHARE_GC_SHARED_C1_CARDTABLEBARRIERSETC1_HPP diff --git a/src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.cpp new file mode 100644 index 00000000000..3eb94314f9c --- /dev/null +++ b/src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/c1/modRefBarrierSetC1.hpp" +#include "utilities/macros.hpp" + +#ifdef ASSERT +#define __ gen->lir(__FILE__, __LINE__)-> +#else +#define __ gen->lir()-> +#endif + +void ModRefBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { + DecoratorSet decorators = access.decorators(); + bool on_array = (decorators & IN_HEAP_ARRAY) != 0; + bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; + + if (access.is_oop()) { + pre_barrier(access, access.resolved_addr(), + LIR_OprFact::illegalOpr /* pre_val */, access.patch_emit_info()); + } + + BarrierSetC1::store_at_resolved(access, value); + + if (access.is_oop()) { + bool precise = on_array || on_anonymous; + LIR_Opr post_addr = precise ? access.resolved_addr() : access.base().opr(); + post_barrier(access, post_addr, value); + } +} + +LIR_Opr ModRefBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { + if (access.is_oop()) { + pre_barrier(access, access.resolved_addr(), + LIR_OprFact::illegalOpr /* pre_val */, NULL); + } + + LIR_Opr result = BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); + + if (access.is_oop()) { + post_barrier(access, access.resolved_addr(), new_value.result()); + } + + return result; +} + +LIR_Opr ModRefBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) { + if (access.is_oop()) { + pre_barrier(access, access.resolved_addr(), + LIR_OprFact::illegalOpr /* pre_val */, NULL); + } + + LIR_Opr result = BarrierSetC1::atomic_xchg_at_resolved(access, value); + + if (access.is_oop()) { + post_barrier(access, access.resolved_addr(), value.result()); + } + + return result; +} + +// This overrides the default to resolve the address into a register, +// assuming it will be used by a write barrier anyway. +LIR_Opr ModRefBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { + DecoratorSet decorators = access.decorators(); + bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; + bool is_write = (decorators & C1_WRITE_ACCESS) != 0; + resolve_in_register |= !needs_patching && is_write && access.is_oop(); + return BarrierSetC1::resolve_address(access, resolve_in_register); +} diff --git a/src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.hpp b/src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.hpp new file mode 100644 index 00000000000..fb65cca83ec --- /dev/null +++ b/src/hotspot/share/gc/shared/c1/modRefBarrierSetC1.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_C1_MODREFBARRIERSETC1_HPP +#define SHARE_GC_SHARED_C1_MODREFBARRIERSETC1_HPP + +#include "gc/shared/c1/barrierSetC1.hpp" + +// The ModRefBarrierSetC1 filters away accesses on BasicTypes other +// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected +// accesses, which are overridden in the concrete BarrierSetAssembler. + +class ModRefBarrierSetC1 : public BarrierSetC1 { +protected: + virtual void pre_barrier(LIRAccess& access, LIR_Opr addr_opr, + LIR_Opr pre_val, CodeEmitInfo* info) {} + virtual void post_barrier(LIRAccess& access, LIR_OprDesc* addr, + LIR_OprDesc* new_val) {} + + virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register); + + virtual void store_at_resolved(LIRAccess& access, LIR_Opr value); + + virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value); + + virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value); +}; + +#endif // SHARE_GC_SHARED_C1_MODREFBARRIERSETC1_HPP diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp index e51a459c525..69e177bc5af 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp @@ -34,15 +34,22 @@ #include "services/memTracker.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "gc/shared/c1/cardTableBarrierSetC1.hpp" +#endif + +class CardTableBarrierSetC1; // This kind of "BarrierSet" allows a "CollectedHeap" to detect and // enumerate ref fields that have been modified (since the last // enumeration.) CardTableBarrierSet::CardTableBarrierSet(BarrierSetAssembler* barrier_set_assembler, + BarrierSetC1* barrier_set_c1, CardTable* card_table, const BarrierSet::FakeRtti& fake_rtti) : ModRefBarrierSet(barrier_set_assembler, + barrier_set_c1, fake_rtti.add_tag(BarrierSet::CardTableBarrierSet)), _defer_initial_card_mark(false), _card_table(card_table) @@ -50,6 +57,7 @@ CardTableBarrierSet::CardTableBarrierSet(BarrierSetAssembler* barrier_set_assemb CardTableBarrierSet::CardTableBarrierSet(CardTable* card_table) : ModRefBarrierSet(make_barrier_set_assembler(), + make_barrier_set_c1(), BarrierSet::FakeRtti(BarrierSet::CardTableBarrierSet)), _defer_initial_card_mark(false), _card_table(card_table) diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp index f20e25f273c..647a380f7f5 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp @@ -53,6 +53,7 @@ class CardTableBarrierSet: public ModRefBarrierSet { CardTable* _card_table; CardTableBarrierSet(BarrierSetAssembler* barrier_set_assembler, + BarrierSetC1* barrier_set_c1, CardTable* card_table, const BarrierSet::FakeRtti& fake_rtti); diff --git a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp index a94eb152c5d..ec4399dddf8 100644 --- a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp @@ -33,8 +33,10 @@ class Klass; class ModRefBarrierSet: public BarrierSet { protected: ModRefBarrierSet(BarrierSetAssembler* barrier_set_assembler, + BarrierSetC1* barrier_set_c1, const BarrierSet::FakeRtti& fake_rtti) : BarrierSet(barrier_set_assembler, + barrier_set_c1, fake_rtti.add_tag(BarrierSet::ModRef)) { } ~ModRefBarrierSet() { } diff --git a/src/hotspot/share/oops/accessBackend.hpp b/src/hotspot/share/oops/accessBackend.hpp index fefc872185b..cef6dbf898e 100644 --- a/src/hotspot/share/oops/accessBackend.hpp +++ b/src/hotspot/share/oops/accessBackend.hpp @@ -980,31 +980,6 @@ namespace AccessInternal { } }; - // This class adds implied decorators that follow according to decorator rules. - // For example adding default reference strength and default memory ordering - // semantics. - template - struct DecoratorFixup: AllStatic { - // If no reference strength has been picked, then strong will be picked - static const DecoratorSet ref_strength_default = input_decorators | - (((ON_DECORATOR_MASK & input_decorators) == 0 && (INTERNAL_VALUE_IS_OOP & input_decorators) != 0) ? - ON_STRONG_OOP_REF : INTERNAL_EMPTY); - // If no memory ordering has been picked, unordered will be picked - static const DecoratorSet memory_ordering_default = ref_strength_default | - ((MO_DECORATOR_MASK & ref_strength_default) == 0 ? MO_UNORDERED : INTERNAL_EMPTY); - // If no barrier strength has been picked, normal will be used - static const DecoratorSet barrier_strength_default = memory_ordering_default | - ((AS_DECORATOR_MASK & memory_ordering_default) == 0 ? AS_NORMAL : INTERNAL_EMPTY); - // Heap array accesses imply it is a heap access - static const DecoratorSet heap_array_is_in_heap = barrier_strength_default | - ((IN_HEAP_ARRAY & barrier_strength_default) != 0 ? IN_HEAP : INTERNAL_EMPTY); - static const DecoratorSet conc_root_is_root = heap_array_is_in_heap | - ((IN_CONCURRENT_ROOT & heap_array_is_in_heap) != 0 ? IN_ROOT : INTERNAL_EMPTY); - static const DecoratorSet archive_root_is_root = conc_root_is_root | - ((IN_ARCHIVE_ROOT & conc_root_is_root) != 0 ? IN_ROOT : INTERNAL_EMPTY); - static const DecoratorSet value = archive_root_is_root | BT_BUILDTIME_DECORATORS; - }; - // Step 2: Reduce types. // Enforce that for non-oop types, T and P have to be strictly the same. // P is the type of the address and T is the type of the values. diff --git a/src/hotspot/share/oops/accessDecorators.hpp b/src/hotspot/share/oops/accessDecorators.hpp index 89779690775..3b4e7aa9ede 100644 --- a/src/hotspot/share/oops/accessDecorators.hpp +++ b/src/hotspot/share/oops/accessDecorators.hpp @@ -25,6 +25,11 @@ #ifndef SHARE_OOPS_ACCESSDECORATORS_HPP #define SHARE_OOPS_ACCESSDECORATORS_HPP +#include "gc/shared/barrierSetConfig.hpp" +#include "memory/allocation.hpp" +#include "metaprogramming/integralConstant.hpp" +#include "utilities/globalDefinitions.hpp" + // A decorator is an attribute or property that affects the way a memory access is performed in some way. // There are different groups of decorators. Some have to do with memory ordering, others to do with, // e.g. strength of references, strength of GC barriers, or whether compression should be applied or not. @@ -216,4 +221,58 @@ const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYC ARRAYCOPY_DISJOINT | ARRAYCOPY_ARRAYOF | ARRAYCOPY_ATOMIC | ARRAYCOPY_ALIGNED; +// Keep track of the last decorator. +const DecoratorSet DECORATOR_LAST = UCONST64(1) << 30; + +namespace AccessInternal { + // This class adds implied decorators that follow according to decorator rules. + // For example adding default reference strength and default memory ordering + // semantics. + template + struct DecoratorFixup: AllStatic { + // If no reference strength has been picked, then strong will be picked + static const DecoratorSet ref_strength_default = input_decorators | + (((ON_DECORATOR_MASK & input_decorators) == 0 && (INTERNAL_VALUE_IS_OOP & input_decorators) != 0) ? + ON_STRONG_OOP_REF : INTERNAL_EMPTY); + // If no memory ordering has been picked, unordered will be picked + static const DecoratorSet memory_ordering_default = ref_strength_default | + ((MO_DECORATOR_MASK & ref_strength_default) == 0 ? MO_UNORDERED : INTERNAL_EMPTY); + // If no barrier strength has been picked, normal will be used + static const DecoratorSet barrier_strength_default = memory_ordering_default | + ((AS_DECORATOR_MASK & memory_ordering_default) == 0 ? AS_NORMAL : INTERNAL_EMPTY); + // Heap array accesses imply it is a heap access + static const DecoratorSet heap_array_is_in_heap = barrier_strength_default | + ((IN_HEAP_ARRAY & barrier_strength_default) != 0 ? IN_HEAP : INTERNAL_EMPTY); + static const DecoratorSet conc_root_is_root = heap_array_is_in_heap | + ((IN_CONCURRENT_ROOT & heap_array_is_in_heap) != 0 ? IN_ROOT : INTERNAL_EMPTY); + static const DecoratorSet archive_root_is_root = conc_root_is_root | + ((IN_ARCHIVE_ROOT & conc_root_is_root) != 0 ? IN_ROOT : INTERNAL_EMPTY); + static const DecoratorSet value = archive_root_is_root | BT_BUILDTIME_DECORATORS; + }; + + // This function implements the above DecoratorFixup rules, but without meta + // programming for code generation that does not use templates. + inline DecoratorSet decorator_fixup(DecoratorSet input_decorators) { + // If no reference strength has been picked, then strong will be picked + DecoratorSet ref_strength_default = input_decorators | + (((ON_DECORATOR_MASK & input_decorators) == 0 && (INTERNAL_VALUE_IS_OOP & input_decorators) != 0) ? + ON_STRONG_OOP_REF : INTERNAL_EMPTY); + // If no memory ordering has been picked, unordered will be picked + DecoratorSet memory_ordering_default = ref_strength_default | + ((MO_DECORATOR_MASK & ref_strength_default) == 0 ? MO_UNORDERED : INTERNAL_EMPTY); + // If no barrier strength has been picked, normal will be used + DecoratorSet barrier_strength_default = memory_ordering_default | + ((AS_DECORATOR_MASK & memory_ordering_default) == 0 ? AS_NORMAL : INTERNAL_EMPTY); + // Heap array accesses imply it is a heap access + DecoratorSet heap_array_is_in_heap = barrier_strength_default | + ((IN_HEAP_ARRAY & barrier_strength_default) != 0 ? IN_HEAP : INTERNAL_EMPTY); + DecoratorSet conc_root_is_root = heap_array_is_in_heap | + ((IN_CONCURRENT_ROOT & heap_array_is_in_heap) != 0 ? IN_ROOT : INTERNAL_EMPTY); + DecoratorSet archive_root_is_root = conc_root_is_root | + ((IN_ARCHIVE_ROOT & conc_root_is_root) != 0 ? IN_ROOT : INTERNAL_EMPTY); + DecoratorSet value = archive_root_is_root | BT_BUILDTIME_DECORATORS; + return value; + } +} + #endif // SHARE_OOPS_ACCESSDECORATORS_HPP diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 51e13b902b6..1386a78a46b 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -206,8 +206,10 @@ #define TIERED #endif #define COMPILER1_PRESENT(code) code +#define NOT_COMPILER1(code) #else // COMPILER1 #define COMPILER1_PRESENT(code) +#define NOT_COMPILER1(code) code #endif // COMPILER1 // COMPILER2 variant From 6cc62b86894a158e53f86cebc4b70f91cf29baed Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 26 Apr 2018 15:41:48 +0200 Subject: [PATCH 062/102] 8202325: [aix] disable warnings-as-errors by default Reviewed-by: goetz, erikj, ihse --- make/autoconf/flags-cflags.m4 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index ac70ffd7813..e29a4db2d7a 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -128,16 +128,22 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS], AC_ARG_ENABLE([warnings-as-errors], [AS_HELP_STRING([--disable-warnings-as-errors], [do not consider native warnings to be an error @<:@enabled@:>@])]) + # Set default value. + if test "x$TOOLCHAIN_TYPE" = xxlc; then + WARNINGS_AS_ERRORS=false + else + WARNINGS_AS_ERRORS=true + fi + AC_MSG_CHECKING([if native warnings are errors]) if test "x$enable_warnings_as_errors" = "xyes"; then AC_MSG_RESULT([yes (explicitly set)]) WARNINGS_AS_ERRORS=true elif test "x$enable_warnings_as_errors" = "xno"; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no (explicitly set)]) WARNINGS_AS_ERRORS=false elif test "x$enable_warnings_as_errors" = "x"; then - AC_MSG_RESULT([yes (default)]) - WARNINGS_AS_ERRORS=true + AC_MSG_RESULT([${WARNINGS_AS_ERRORS} (default)]) else AC_MSG_ERROR([--enable-warnings-as-errors accepts no argument]) fi From 1787461d8a6039fcc41980972b194a7cc29bdd47 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 27 Apr 2018 07:59:29 +0200 Subject: [PATCH 063/102] 8202179: Compilation fails with assert(n->is_expensive()) failed: expensive nodes with non-null control here only Only treat the SqrtFNode as expensive if the control input is not NULL. Reviewed-by: kvn, roland --- src/hotspot/share/opto/node.cpp | 2 +- src/hotspot/share/opto/subnode.hpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index b2838b13567..f3142cec254 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -700,7 +700,7 @@ bool Node::is_dead() const { //------------------------------is_unreachable--------------------------------- bool Node::is_unreachable(PhaseIterGVN &igvn) const { assert(!is_Mach(), "doesn't work with MachNodes"); - return outcnt() == 0 || igvn.type(this) == Type::TOP || in(0)->is_top(); + return outcnt() == 0 || igvn.type(this) == Type::TOP || (in(0) != NULL && in(0)->is_top()); } //------------------------------add_req---------------------------------------- diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index 216956dceea..3a64b40021b 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -448,7 +448,12 @@ class SqrtFNode : public Node { public: SqrtFNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { init_flags(Flag_is_expensive); - C->add_expensive_node(this); + if (c != NULL) { + // Treat node only as expensive if a control input is set because it might + // be created from a SqrtDNode in ConvD2FNode::Ideal() that was found to + // be unique and therefore has no control input. + C->add_expensive_node(this); + } } virtual int Opcode() const; const Type *bottom_type() const { return Type::FLOAT; } From 0432a1081e858b2c3d3e5a6595465872ef640381 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 27 Apr 2018 03:57:00 -0400 Subject: [PATCH 064/102] 8202230: Provide accessors for JNIHandles storage objects Add JNIHandles::[weak_]global_handles(). Reviewed-by: coleenp, tschatzl --- src/hotspot/share/runtime/jniHandles.cpp | 42 ++++++++++++++---------- src/hotspot/share/runtime/jniHandles.hpp | 3 ++ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index ed99d6e65c2..60240081157 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -39,6 +39,16 @@ OopStorage* JNIHandles::_global_handles = NULL; OopStorage* JNIHandles::_weak_global_handles = NULL; +OopStorage* JNIHandles::global_handles() { + assert(_global_handles != NULL, "Uninitialized JNI global handles"); + return _global_handles; +} + +OopStorage* JNIHandles::weak_global_handles() { + assert(_weak_global_handles != NULL, "Uninitialized JNI weak global handles"); + return _weak_global_handles; +} + jobject JNIHandles::make_local(oop obj) { if (obj == NULL) { @@ -96,7 +106,7 @@ jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) { if (!obj.is_null()) { // ignore null handles assert(oopDesc::is_oop(obj()), "not an oop"); - oop* ptr = _global_handles->allocate(); + oop* ptr = global_handles()->allocate(); // Return NULL on allocation failure. if (ptr != NULL) { assert(*ptr == NULL, "invariant"); @@ -120,7 +130,7 @@ jobject JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) { if (!obj.is_null()) { // ignore null handles assert(oopDesc::is_oop(obj()), "not an oop"); - oop* ptr = _weak_global_handles->allocate(); + oop* ptr = weak_global_handles()->allocate(); // Return NULL on allocation failure. if (ptr != NULL) { assert(*ptr == NULL, "invariant"); @@ -167,7 +177,7 @@ void JNIHandles::destroy_global(jobject handle) { assert(!is_jweak(handle), "wrong method for detroying jweak"); oop* oop_ptr = jobject_ptr(handle); RootAccess::oop_store(oop_ptr, (oop)NULL); - _global_handles->release(oop_ptr); + global_handles()->release(oop_ptr); } } @@ -177,23 +187,23 @@ void JNIHandles::destroy_weak_global(jobject handle) { assert(is_jweak(handle), "JNI handle not jweak"); oop* oop_ptr = jweak_ptr(handle); RootAccess::oop_store(oop_ptr, (oop)NULL); - _weak_global_handles->release(oop_ptr); + weak_global_handles()->release(oop_ptr); } } void JNIHandles::oops_do(OopClosure* f) { - _global_handles->oops_do(f); + global_handles()->oops_do(f); } void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { - _weak_global_handles->weak_oops_do(is_alive, f); + weak_global_handles()->weak_oops_do(is_alive, f); } void JNIHandles::weak_oops_do(OopClosure* f) { - _weak_global_handles->weak_oops_do(f); + weak_global_handles()->weak_oops_do(f); } @@ -216,11 +226,11 @@ jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) { assert(handle != NULL, "precondition"); jobjectRefType result = JNIInvalidRefType; if (is_jweak(handle)) { - if (is_storage_handle(_weak_global_handles, jweak_ptr(handle))) { + if (is_storage_handle(weak_global_handles(), jweak_ptr(handle))) { result = JNIWeakGlobalRefType; } } else { - switch (_global_handles->allocation_status(jobject_ptr(handle))) { + switch (global_handles()->allocation_status(jobject_ptr(handle))) { case OopStorage::ALLOCATED_ENTRY: result = JNIGlobalRefType; break; @@ -277,33 +287,31 @@ bool JNIHandles::is_frame_handle(JavaThread* thr, jobject handle) { bool JNIHandles::is_global_handle(jobject handle) { assert(handle != NULL, "precondition"); - return !is_jweak(handle) && is_storage_handle(_global_handles, jobject_ptr(handle)); + return !is_jweak(handle) && is_storage_handle(global_handles(), jobject_ptr(handle)); } bool JNIHandles::is_weak_global_handle(jobject handle) { assert(handle != NULL, "precondition"); - return is_jweak(handle) && is_storage_handle(_weak_global_handles, jweak_ptr(handle)); + return is_jweak(handle) && is_storage_handle(weak_global_handles(), jweak_ptr(handle)); } size_t JNIHandles::global_handle_memory_usage() { - return _global_handles->total_memory_usage(); + return global_handles()->total_memory_usage(); } size_t JNIHandles::weak_global_handle_memory_usage() { - return _weak_global_handles->total_memory_usage(); + return weak_global_handles()->total_memory_usage(); } // We assume this is called at a safepoint: no lock is needed. void JNIHandles::print_on(outputStream* st) { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - assert(_global_handles != NULL && _weak_global_handles != NULL, - "JNIHandles not initialized"); st->print_cr("JNI global refs: " SIZE_FORMAT ", weak refs: " SIZE_FORMAT, - _global_handles->allocation_count(), - _weak_global_handles->allocation_count()); + global_handles()->allocation_count(), + weak_global_handles()->allocation_count()); st->cr(); st->flush(); } diff --git a/src/hotspot/share/runtime/jniHandles.hpp b/src/hotspot/share/runtime/jniHandles.hpp index d48cf7d6a5b..3c6be3b6b1a 100644 --- a/src/hotspot/share/runtime/jniHandles.hpp +++ b/src/hotspot/share/runtime/jniHandles.hpp @@ -115,6 +115,9 @@ class JNIHandles : AllStatic { static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f); // Traversal of weak global handles. static void weak_oops_do(OopClosure* f); + + static OopStorage* global_handles(); + static OopStorage* weak_global_handles(); }; From 893bd31647bf8f33c3a21cf147851ca14f9333b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Fri, 27 Apr 2018 10:59:46 +0200 Subject: [PATCH 065/102] 8202082: Remove explicit CMS checks in CardTableBarrierSetAssembler Reviewed-by: shade, kbarrett --- .../cardTableBarrierSetAssembler_aarch64.cpp | 4 ++-- .../shared/cardTableBarrierSetAssembler_ppc.cpp | 6 ++++-- .../shared/cardTableBarrierSetAssembler_x86.cpp | 17 +++++++++-------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp index 1b448588a69..1ed0eb8b0a8 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp @@ -56,7 +56,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob __ strb(zr, Address(obj, rscratch1)); __ bind(L_already_dirty); } else { - if (UseConcMarkSweepGC && CMSPrecleaningEnabled) { + if (ct->scanned_concurrently()) { __ membar(Assembler::StoreStore); } __ strb(zr, Address(obj, rscratch1)); @@ -79,7 +79,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl const Register count = end; // 'end' register contains bytes count now __ load_byte_map_base(scratch); __ add(start, start, scratch); - if (UseConcMarkSweepGC) { + if (ct->scanned_concurrently()) { __ membar(__ StoreStore); } __ bind(L_loop); diff --git a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp index 3bd2e6b1097..5c5afa867d9 100644 --- a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp @@ -50,7 +50,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl Label Lskip_loop, Lstore_loop; - if (UseConcMarkSweepGC) { __ membar(Assembler::StoreStore); } + if (ct->scanned_concurrently()) { __ membar(Assembler::StoreStore); } __ sldi_(count, count, LogBytesPerHeapOop); __ beq(CCR0, Lskip_loop); // zero length @@ -75,11 +75,13 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm, jbyte* byte_map_base, Register tmp, Register obj) { + CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); + CardTable* ct = ctbs->card_table(); assert_different_registers(obj, tmp, R0); __ load_const_optimized(tmp, (address)byte_map_base, R0); __ srdi(obj, obj, CardTable::card_shift); __ li(R0, CardTable::dirty_card_val()); - if (UseConcMarkSweepGC) { __ membar(Assembler::StoreStore); } + if (ct->scanned_concurrently()) { __ membar(Assembler::StoreStore); } __ stbx(R0, tmp, obj); } diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 600ef81228b..94101ea9fd2 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -90,8 +90,9 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob // register obj is destroyed afterwards. BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ct = barrier_set_cast(bs); - assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code"); + CardTableBarrierSet* ctbs = barrier_set_cast(bs); + CardTable* ct = ctbs->card_table(); + assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code"); __ shrptr(obj, CardTable::card_shift); @@ -102,15 +103,15 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob // So this essentially converts an address to a displacement and it will // never need to be relocated. On 64bit however the value may be too // large for a 32bit displacement. - intptr_t disp = (intptr_t) ct->card_table()->byte_map_base(); - if (__ is_simm32(disp)) { - card_addr = Address(noreg, obj, Address::times_1, disp); + intptr_t byte_map_base = (intptr_t)ct->byte_map_base(); + if (__ is_simm32(byte_map_base)) { + card_addr = Address(noreg, obj, Address::times_1, byte_map_base); } else { - // By doing it as an ExternalAddress 'disp' could be converted to a rip-relative + // By doing it as an ExternalAddress 'byte_map_base' could be converted to a rip-relative // displacement and done in a single instruction given favorable mapping and a // smarter version of as_Address. However, 'ExternalAddress' generates a relocation // entry and that entry is not properly handled by the relocation code. - AddressLiteral cardtable((address)ct->card_table()->byte_map_base(), relocInfo::none); + AddressLiteral cardtable((address)byte_map_base, relocInfo::none); Address index(noreg, obj, Address::times_1); card_addr = __ as_Address(ArrayAddress(cardtable, index)); } @@ -118,7 +119,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob int dirty = CardTable::dirty_card_val(); if (UseCondCardMark) { Label L_already_dirty; - if (UseConcMarkSweepGC) { + if (ct->scanned_concurrently()) { __ membar(Assembler::StoreLoad); } __ cmpb(card_addr, dirty); From 0f583c7817369e9faf557354a66629e81cad5a0c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 27 Apr 2018 12:06:46 +0200 Subject: [PATCH 066/102] 6672778: G1 should trim task queues more aggressively during evacuation pauses Regularly try to drain task queues. This helps memory usage and performance during garbage collection. Reviewed-by: sjohanss, sangheki --- .../share/gc/g1/bufferingOopClosure.hpp | 144 ---------- src/hotspot/share/gc/g1/g1Arguments.cpp | 5 + src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 17 +- src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 70 ++++- src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp | 33 ++- src/hotspot/share/gc/g1/g1OopClosures.cpp | 4 +- src/hotspot/share/gc/g1/g1OopClosures.hpp | 4 + .../share/gc/g1/g1OopClosures.inline.hpp | 9 + .../share/gc/g1/g1ParScanThreadState.cpp | 24 +- .../share/gc/g1/g1ParScanThreadState.hpp | 21 +- .../gc/g1/g1ParScanThreadState.inline.hpp | 43 +++ src/hotspot/share/gc/g1/g1Policy.cpp | 8 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 123 +++++---- src/hotspot/share/gc/g1/g1RemSet.hpp | 42 +-- src/hotspot/share/gc/g1/g1RootClosures.cpp | 21 +- src/hotspot/share/gc/g1/g1RootClosures.hpp | 6 +- src/hotspot/share/gc/g1/g1RootProcessor.cpp | 19 +- src/hotspot/share/gc/g1/g1RootProcessor.hpp | 7 +- src/hotspot/share/gc/g1/g1SharedClosures.hpp | 5 +- src/hotspot/share/gc/shared/taskqueue.hpp | 9 +- .../share/gc/shared/taskqueue.inline.hpp | 4 +- src/hotspot/share/utilities/ticks.hpp | 5 + src/hotspot/share/utilities/ticks.inline.hpp | 5 + .../gtest/gc/g1/test_bufferingOopClosure.cpp | 257 ------------------ 24 files changed, 315 insertions(+), 570 deletions(-) delete mode 100644 src/hotspot/share/gc/g1/bufferingOopClosure.hpp delete mode 100644 test/hotspot/gtest/gc/g1/test_bufferingOopClosure.cpp diff --git a/src/hotspot/share/gc/g1/bufferingOopClosure.hpp b/src/hotspot/share/gc/g1/bufferingOopClosure.hpp deleted file mode 100644 index 58081684f42..00000000000 --- a/src/hotspot/share/gc/g1/bufferingOopClosure.hpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2001, 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_GC_G1_BUFFERINGOOPCLOSURE_HPP -#define SHARE_VM_GC_G1_BUFFERINGOOPCLOSURE_HPP - -#include "memory/iterator.hpp" -#include "oops/oopsHierarchy.hpp" -#include "runtime/os.hpp" -#include "utilities/debug.hpp" - -// A BufferingOops closure tries to separate out the cost of finding roots -// from the cost of applying closures to them. It maintains an array of -// ref-containing locations. Until the array is full, applying the closure -// to an oop* merely records that location in the array. Since this -// closure app cost is small, an elapsed timer can approximately attribute -// all of this cost to the cost of finding the roots. When the array fills -// up, the wrapped closure is applied to all elements, keeping track of -// this elapsed time of this process, and leaving the array empty. -// The caller must be sure to call "done" to process any unprocessed -// buffered entries. - -class BufferingOopClosure: public OopClosure { - friend class BufferingOopClosureTest; -protected: - static const size_t BufferLength = 1024; - - // We need to know if the buffered addresses contain oops or narrowOops. - // We can't tag the addresses the way StarTask does, because we need to - // be able to handle unaligned addresses coming from oops embedded in code. - // - // The addresses for the full-sized oops are filled in from the bottom, - // while the addresses for the narrowOops are filled in from the top. - OopOrNarrowOopStar _buffer[BufferLength]; - OopOrNarrowOopStar* _oop_top; - OopOrNarrowOopStar* _narrowOop_bottom; - - OopClosure* _oc; - double _closure_app_seconds; - - - bool is_buffer_empty() { - return _oop_top == _buffer && _narrowOop_bottom == (_buffer + BufferLength - 1); - } - - bool is_buffer_full() { - return _narrowOop_bottom < _oop_top; - } - - // Process addresses containing full-sized oops. - void process_oops() { - for (OopOrNarrowOopStar* curr = _buffer; curr < _oop_top; ++curr) { - _oc->do_oop((oop*)(*curr)); - } - _oop_top = _buffer; - } - - // Process addresses containing narrow oops. - void process_narrowOops() { - for (OopOrNarrowOopStar* curr = _buffer + BufferLength - 1; curr > _narrowOop_bottom; --curr) { - _oc->do_oop((narrowOop*)(*curr)); - } - _narrowOop_bottom = _buffer + BufferLength - 1; - } - - // Apply the closure to all oops and clear the buffer. - // Accumulate the time it took. - void process_buffer() { - double start = os::elapsedTime(); - - process_oops(); - process_narrowOops(); - - _closure_app_seconds += (os::elapsedTime() - start); - } - - void process_buffer_if_full() { - if (is_buffer_full()) { - process_buffer(); - } - } - - void add_narrowOop(narrowOop* p) { - assert(!is_buffer_full(), "Buffer should not be full"); - *_narrowOop_bottom = (OopOrNarrowOopStar)p; - _narrowOop_bottom--; - } - - void add_oop(oop* p) { - assert(!is_buffer_full(), "Buffer should not be full"); - *_oop_top = (OopOrNarrowOopStar)p; - _oop_top++; - } - -public: - virtual void do_oop(narrowOop* p) { - process_buffer_if_full(); - add_narrowOop(p); - } - - virtual void do_oop(oop* p) { - process_buffer_if_full(); - add_oop(p); - } - - void done() { - if (!is_buffer_empty()) { - process_buffer(); - } - } - - double closure_app_seconds() { - return _closure_app_seconds; - } - - BufferingOopClosure(OopClosure *oc) : - _oc(oc), - _oop_top(_buffer), - _narrowOop_bottom(_buffer + BufferLength - 1), - _closure_app_seconds(0.0) { } -}; - -#endif // SHARE_VM_GC_G1_BUFFERINGOOPCLOSURE_HPP diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index d16482e5447..8c3cad3438c 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -126,6 +126,11 @@ void G1Arguments::initialize() { log_trace(gc)("MarkStackSize: %uk MarkStackSizeMax: %uk", (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); + // By default do not let the target stack size to be more than 1/4 of the entries + if (FLAG_IS_DEFAULT(GCDrainStackTargetSize)) { + FLAG_SET_ERGO(uintx, GCDrainStackTargetSize, MIN2(GCDrainStackTargetSize, (uintx)TASKQUEUE_SIZE / 4)); + } + #ifdef COMPILER2 // Enable loop strip mining to offer better pause time guarantees if (FLAG_IS_DEFAULT(UseCountedLoopSafepoints)) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 4078ff9bfa5..ed1b378ee83 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -28,7 +28,6 @@ #include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" #include "code/icBuffer.hpp" -#include "gc/g1/bufferingOopClosure.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" @@ -1841,7 +1840,7 @@ void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, uint while (dcqs.apply_closure_during_gc(cl, worker_i)) { n_completed_buffers++; } - g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, n_completed_buffers); + g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, n_completed_buffers, G1GCPhaseTimes::UpdateRSProcessedBuffers); dcqs.clear_n_completed_buffers(); assert(!dcqs.completed_buffers_exist_dirty(), "Completed buffers exist!"); } @@ -3130,15 +3129,13 @@ public: double start_strong_roots_sec = os::elapsedTime(); - _root_processor->evacuate_roots(pss->closures(), worker_id); + _root_processor->evacuate_roots(pss, worker_id); // We pass a weak code blobs closure to the remembered set scanning because we want to avoid // treating the nmethods visited to act as roots for concurrent marking. // We only want to make sure that the oops in the nmethods are adjusted with regard to the // objects copied by the current evacuation. - _g1h->g1_rem_set()->oops_into_collection_set_do(pss, - pss->closures()->weak_codeblobs(), - worker_id); + _g1h->g1_rem_set()->oops_into_collection_set_do(pss, worker_id); double strong_roots_sec = os::elapsedTime() - start_strong_roots_sec; @@ -3152,9 +3149,11 @@ public: evac_term_attempts = evac.term_attempts(); term_sec = evac.term_time(); double elapsed_sec = os::elapsedTime() - start; - _g1h->g1_policy()->phase_times()->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_id, elapsed_sec - term_sec); - _g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::Termination, worker_id, term_sec); - _g1h->g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, evac_term_attempts); + + G1GCPhaseTimes* p = _g1h->g1_policy()->phase_times(); + p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_id, elapsed_sec - term_sec); + p->record_time_secs(G1GCPhaseTimes::Termination, worker_id, term_sec); + p->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, evac_term_attempts); } assert(pss->queue_is_empty(), "should be empty"); diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index 7dd43bdfbd7..c26bafa48ea 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HotCardCache.hpp" +#include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/shared/workerDataArray.inline.hpp" #include "memory/resourceArea.hpp" @@ -167,9 +168,12 @@ void G1GCPhaseTimes::note_gc_start() { } #define ASSERT_PHASE_UNINITIALIZED(phase) \ - assert(_gc_par_phases[phase]->get(i) == uninitialized, "Phase " #phase " reported for thread that was not started"); + assert(_gc_par_phases[phase] == NULL || _gc_par_phases[phase]->get(i) == uninitialized, "Phase " #phase " reported for thread that was not started"); double G1GCPhaseTimes::worker_time(GCParPhases phase, uint worker) { + if (_gc_par_phases[phase] == NULL) { + return 0.0; + } double value = _gc_par_phases[phase]->get(worker); if (value != WorkerDataArray::uninitialized()) { return value; @@ -189,21 +193,20 @@ void G1GCPhaseTimes::note_gc_end() { double total_worker_time = _gc_par_phases[GCWorkerEnd]->get(i) - _gc_par_phases[GCWorkerStart]->get(i); record_time_secs(GCWorkerTotal, i , total_worker_time); - double worker_known_time = - worker_time(ExtRootScan, i) - + worker_time(SATBFiltering, i) - + worker_time(UpdateRS, i) - + worker_time(ScanRS, i) - + worker_time(CodeRoots, i) - + worker_time(ObjCopy, i) - + worker_time(Termination, i); + double worker_known_time = worker_time(ExtRootScan, i) + + worker_time(ScanHCC, i) + + worker_time(UpdateRS, i) + + worker_time(ScanRS, i) + + worker_time(CodeRoots, i) + + worker_time(ObjCopy, i) + + worker_time(Termination, i); record_time_secs(Other, i, total_worker_time - worker_known_time); } else { // Make sure all slots are uninitialized since this thread did not seem to have been started ASSERT_PHASE_UNINITIALIZED(GCWorkerEnd); ASSERT_PHASE_UNINITIALIZED(ExtRootScan); - ASSERT_PHASE_UNINITIALIZED(SATBFiltering); + ASSERT_PHASE_UNINITIALIZED(ScanHCC); ASSERT_PHASE_UNINITIALIZED(UpdateRS); ASSERT_PHASE_UNINITIALIZED(ScanRS); ASSERT_PHASE_UNINITIALIZED(CodeRoots); @@ -225,6 +228,14 @@ void G1GCPhaseTimes::add_time_secs(GCParPhases phase, uint worker_i, double secs _gc_par_phases[phase]->add(worker_i, secs); } +void G1GCPhaseTimes::record_or_add_objcopy_time_secs(uint worker_i, double secs) { + if (_gc_par_phases[ObjCopy]->get(worker_i) == _gc_par_phases[ObjCopy]->uninitialized()) { + record_time_secs(ObjCopy, worker_i, secs); + } else { + add_time_secs(ObjCopy, worker_i, secs); + } +} + void G1GCPhaseTimes::record_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index) { _gc_par_phases[phase]->set_thread_work_item(worker_i, count, index); } @@ -463,16 +474,49 @@ void G1GCPhaseTimes::print() { } } +G1EvacPhaseWithTrimTimeTracker::G1EvacPhaseWithTrimTimeTracker(G1ParScanThreadState* pss, Tickspan& total_time, Tickspan& trim_time) : + _pss(pss), + _start(Ticks::now()), + _total_time(total_time), + _trim_time(trim_time) { + + assert(_pss->trim_ticks().value() == 0, "Possibly remaining trim ticks left over from previous use"); +} + +G1EvacPhaseWithTrimTimeTracker::~G1EvacPhaseWithTrimTimeTracker() { + _total_time += (Ticks::now() - _start) - _pss->trim_ticks(); + _trim_time += _pss->trim_ticks(); + _pss->reset_trim_ticks(); +} + G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id) : _phase_times(phase_times), _phase(phase), _worker_id(worker_id) { if (_phase_times != NULL) { - _start_time = os::elapsedTime(); + _start_time = Ticks::now(); } } G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() { if (_phase_times != NULL) { - _phase_times->record_time_secs(_phase, _worker_id, os::elapsedTime() - _start_time); + _phase_times->record_time_secs(_phase, _worker_id, TicksToTimeHelper::seconds(Ticks::now() - _start_time)); + } +} + +G1EvacPhaseTimesTracker::G1EvacPhaseTimesTracker(G1GCPhaseTimes* phase_times, + G1ParScanThreadState* pss, + G1GCPhaseTimes::GCParPhases phase, + uint worker_id) : + G1GCParPhaseTimesTracker(phase_times, phase, worker_id), + _total_time(), + _trim_time(), + _trim_tracker(pss, _total_time, _trim_time) { +} + +G1EvacPhaseTimesTracker::~G1EvacPhaseTimesTracker() { + if (_phase_times != NULL) { + // Exclude trim time by increasing the start time. + _start_time += _trim_time; + _phase_times->record_or_add_objcopy_time_secs(_worker_id, TicksToTimeHelper::seconds(_trim_time)); } } diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index b59e3aeb83c..bebd673e010 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "utilities/macros.hpp" class LineBuffer; +class G1ParScanThreadState; class STWGCTimer; template class WorkerDataArray; @@ -198,6 +199,8 @@ class G1GCPhaseTimes : public CHeapObj { // add a number of seconds to a phase void add_time_secs(GCParPhases phase, uint worker_i, double secs); + void record_or_add_objcopy_time_secs(uint worker_i, double secs); + void record_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index = 0); // return the average time for a phase in milliseconds @@ -369,14 +372,36 @@ class G1GCPhaseTimes : public CHeapObj { ReferenceProcessorPhaseTimes* ref_phase_times() { return &_ref_phase_times; } }; -class G1GCParPhaseTimesTracker : public StackObj { - double _start_time; +class G1EvacPhaseWithTrimTimeTracker : public StackObj { + G1ParScanThreadState* _pss; + Ticks _start; + + Tickspan& _total_time; + Tickspan& _trim_time; +public: + G1EvacPhaseWithTrimTimeTracker(G1ParScanThreadState* pss, Tickspan& total_time, Tickspan& trim_time); + ~G1EvacPhaseWithTrimTimeTracker(); +}; + +class G1GCParPhaseTimesTracker : public CHeapObj { +protected: + Ticks _start_time; G1GCPhaseTimes::GCParPhases _phase; G1GCPhaseTimes* _phase_times; uint _worker_id; public: G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id); - ~G1GCParPhaseTimesTracker(); + virtual ~G1GCParPhaseTimesTracker(); +}; + +class G1EvacPhaseTimesTracker : public G1GCParPhaseTimesTracker { + Tickspan _total_time; + Tickspan _trim_time; + + G1EvacPhaseWithTrimTimeTracker _trim_tracker; +public: + G1EvacPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1ParScanThreadState* pss, G1GCPhaseTimes::GCParPhases phase, uint worker_id); + virtual ~G1EvacPhaseTimesTracker(); }; #endif // SHARE_VM_GC_G1_G1GCPHASETIMES_HPP diff --git a/src/hotspot/share/gc/g1/g1OopClosures.cpp b/src/hotspot/share/gc/g1/g1OopClosures.cpp index fda434657fa..881a3fe5f3a 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.cpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,8 @@ void G1CLDScanClosure::do_cld(ClassLoaderData* cld) { cld->oops_do(_closure, _must_claim, /*clear_modified_oops*/true); _closure->set_scanned_cld(NULL); + + _closure->trim_queue_partially(); } _count++; } diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index cf07a90eacd..a1cd36549fd 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -57,6 +57,8 @@ public: // This closure needs special handling for InstanceRefKlass. virtual ReferenceIterationMode reference_iteration_mode() { return DO_DISCOVERED_AND_DISCOVERY; } void set_region(HeapRegion* from) { _from = from; } + + inline void trim_queue_partially(); }; // Used during the Update RS phase to refine remaining cards in the DCQ during garbage collection. @@ -126,6 +128,8 @@ protected: public: void set_scanned_cld(ClassLoaderData* cld) { _scanned_cld = cld; } inline void do_cld_barrier(oop new_obj); + + inline void trim_queue_partially(); }; enum G1Barrier { diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 49a638aea07..03e59a6032d 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -67,6 +67,10 @@ inline void G1ScanClosureBase::handle_non_cset_obj_common(InCSetState const stat } } +inline void G1ScanClosureBase::trim_queue_partially() { + _par_scan_state->trim_queue_partially(); +} + template inline void G1ScanEvacuatedObjClosure::do_oop_nv(T* p) { T heap_oop = RawAccess<>::oop_load(p); @@ -225,6 +229,10 @@ void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { _cm->mark_in_next_bitmap(_worker_id, to_obj, from_obj->size()); } +void G1ParCopyHelper::trim_queue_partially() { + _par_scan_state->trim_queue_partially(); +} + template template void G1ParCopyClosure::do_oop_work(T* p) { @@ -269,6 +277,7 @@ void G1ParCopyClosure::do_oop_work(T* p) { mark_object(obj); } } + trim_queue_partially(); } template void G1RebuildRemSetClosure::do_oop_nv(T* p) { diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 268950cf252..10d918b1997 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -43,11 +43,15 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, _dcq(&g1h->dirty_card_queue_set()), _ct(g1h->card_table()), _closures(NULL), + _plab_allocator(NULL), + _age_table(false), + _tenuring_threshold(g1h->g1_policy()->tenuring_threshold()), + _scanner(g1h, this), _hash_seed(17), _worker_id(worker_id), - _tenuring_threshold(g1h->g1_policy()->tenuring_threshold()), - _age_table(false), - _scanner(g1h, this), + _stack_trim_upper_threshold(GCDrainStackTargetSize * 2 + 1), + _stack_trim_lower_threshold(GCDrainStackTargetSize), + _trim_ticks(), _old_gen_is_full(false) { // we allocate G1YoungSurvRateNumRegions plus one entries, since @@ -138,16 +142,8 @@ bool G1ParScanThreadState::verify_task(StarTask ref) const { void G1ParScanThreadState::trim_queue() { StarTask ref; do { - // Drain the overflow stack first, so other threads can steal. - while (_refs->pop_overflow(ref)) { - if (!_refs->try_push_to_taskqueue(ref)) { - dispatch_reference(ref); - } - } - - while (_refs->pop_local(ref)) { - dispatch_reference(ref); - } + // Fully drain the queue. + trim_queue_to_threshold(0); } while (!_refs->is_empty()); } @@ -314,7 +310,7 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state, // length field of the from-space object. arrayOop(obj)->set_length(0); oop* old_p = set_partial_array_mask(old); - push_on_queue(old_p); + do_oop_partial_array(old_p); } else { HeapRegion* const to_region = _g1h->heap_region_containing(obj_ptr); _scanner.set_region(to_region); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index e5315933b57..7e6369269a0 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -35,6 +35,7 @@ #include "gc/shared/ageTable.hpp" #include "memory/allocation.hpp" #include "oops/oop.hpp" +#include "utilities/ticks.hpp" class G1PLABAllocator; class G1EvacuationRootClosures; @@ -42,7 +43,6 @@ class HeapRegion; class outputStream; class G1ParScanThreadState : public CHeapObj { - private: G1CollectedHeap* _g1h; RefToScanQueue* _refs; DirtyCardQueue _dcq; @@ -60,6 +60,11 @@ class G1ParScanThreadState : public CHeapObj { int _hash_seed; uint _worker_id; + // Upper and lower threshold to start and end work queue draining. + uint const _stack_trim_upper_threshold; + uint const _stack_trim_lower_threshold; + + Tickspan _trim_ticks; // Map from young-age-index (0 == not young, 1 is youngest) to // surviving words. base is what we get back from the malloc call size_t* _surviving_young_words_base; @@ -83,7 +88,7 @@ class G1ParScanThreadState : public CHeapObj { return _dest[original.value()]; } - public: +public: G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, size_t young_cset_length); virtual ~G1ParScanThreadState(); @@ -129,7 +134,7 @@ class G1ParScanThreadState : public CHeapObj { void flush(size_t* surviving_young_words); - private: +private: #define G1_PARTIAL_ARRAY_MASK 0x2 inline bool has_partial_array_mask(oop* ref) const { @@ -185,11 +190,19 @@ class G1ParScanThreadState : public CHeapObj { void report_promotion_event(InCSetState const dest_state, oop const old, size_t word_sz, uint age, HeapWord * const obj_ptr) const; - public: + inline bool needs_partial_trimming() const; + inline bool is_partially_trimmed() const; + + inline void trim_queue_to_threshold(uint threshold); +public: oop copy_to_survivor_space(InCSetState const state, oop const obj, markOop const old_mark); void trim_queue(); + void trim_queue_partially(); + + Tickspan trim_ticks() const; + void reset_trim_ticks(); inline void steal_and_trim_queue(RefToScanQueueSet *task_queues); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp index 89b5758e364..06eb276a08a 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -29,6 +29,7 @@ #include "gc/g1/g1RemSet.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" +#include "utilities/ticks.inline.hpp" template void G1ParScanThreadState::do_oop_evac(T* p) { // Reference should not be NULL here as such are never pushed to the task queue. @@ -151,4 +152,46 @@ void G1ParScanThreadState::steal_and_trim_queue(RefToScanQueueSet *task_queues) } } +inline bool G1ParScanThreadState::needs_partial_trimming() const { + return !_refs->overflow_empty() || _refs->size() > _stack_trim_upper_threshold; +} + +inline bool G1ParScanThreadState::is_partially_trimmed() const { + return _refs->overflow_empty() && _refs->size() <= _stack_trim_lower_threshold; +} + +inline void G1ParScanThreadState::trim_queue_to_threshold(uint threshold) { + StarTask ref; + // Drain the overflow stack first, so other threads can potentially steal. + while (_refs->pop_overflow(ref)) { + if (!_refs->try_push_to_taskqueue(ref)) { + dispatch_reference(ref); + } + } + + while (_refs->pop_local(ref, threshold)) { + dispatch_reference(ref); + } +} + +inline void G1ParScanThreadState::trim_queue_partially() { + if (!needs_partial_trimming()) { + return; + } + + const Ticks start = Ticks::now(); + do { + trim_queue_to_threshold(_stack_trim_lower_threshold); + } while (!is_partially_trimmed()); + _trim_ticks += Ticks::now() - start; +} + +inline Tickspan G1ParScanThreadState::trim_ticks() const { + return _trim_ticks; +} + +inline void G1ParScanThreadState::reset_trim_ticks() { + _trim_ticks = Tickspan(); +} + #endif // SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 28da4ba7c11..4f882a1fb20 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -628,7 +628,7 @@ void G1Policy::record_collection_pause_end(double pause_time_ms, size_t cards_sc if (update_stats) { double cost_per_card_ms = 0.0; if (_pending_cards > 0) { - cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms) / (double) _pending_cards; + cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS)) / (double) _pending_cards; _analytics->report_cost_per_card_ms(cost_per_card_ms); } _analytics->report_cost_scan_hcc(scan_hcc_time_ms); @@ -730,9 +730,9 @@ void G1Policy::record_collection_pause_end(double pause_time_ms, size_t cards_sc } else { update_rs_time_goal_ms -= scan_hcc_time_ms; } - _g1h->concurrent_refine()->adjust(average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms, - phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), - update_rs_time_goal_ms); + _g1h->concurrent_refine()->adjust(average_time_ms(G1GCPhaseTimes::UpdateRS), + phase_times()->sum_thread_work_items(G1GCPhaseTimes::UpdateRS), + update_rs_time_goal_ms); cset_chooser()->verify(); } diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 77e3955a2b0..9e3fcb3e8c1 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -33,6 +33,7 @@ #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HotCardCache.hpp" #include "gc/g1/g1OopClosures.inline.hpp" +#include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RemSet.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" @@ -306,32 +307,21 @@ void G1RemSet::initialize(size_t capacity, uint max_regions) { G1ScanRSForRegionClosure::G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, G1ScanObjsDuringScanRSClosure* scan_obj_on_card, - CodeBlobClosure* code_root_cl, + G1ParScanThreadState* pss, uint worker_i) : - _scan_state(scan_state), + _g1h(G1CollectedHeap::heap()), + _ct(_g1h->card_table()), + _pss(pss), _scan_objs_on_card_cl(scan_obj_on_card), - _code_root_cl(code_root_cl), - _strong_code_root_scan_time_sec(0.0), + _scan_state(scan_state), + _worker_i(worker_i), _cards_claimed(0), _cards_scanned(0), _cards_skipped(0), - _worker_i(worker_i) { - _g1h = G1CollectedHeap::heap(); - _bot = _g1h->bot(); - _ct = _g1h->card_table(); -} - -void G1ScanRSForRegionClosure::scan_card(MemRegion mr, uint region_idx_for_card) { - HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); - _scan_objs_on_card_cl->set_region(card_region); - card_region->oops_on_card_seq_iterate_careful(mr, _scan_objs_on_card_cl); - _cards_scanned++; -} - -void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) { - double scan_start = os::elapsedTime(); - r->strong_code_roots_do(_code_root_cl); - _strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start); + _rem_set_root_scan_time(), + _rem_set_trim_partially_time(), + _strong_code_root_scan_time(), + _strong_code_trim_partially_time() { } void G1ScanRSForRegionClosure::claim_card(size_t card_index, const uint region_idx_for_card){ @@ -339,13 +329,17 @@ void G1ScanRSForRegionClosure::claim_card(size_t card_index, const uint region_i _scan_state->add_dirty_region(region_idx_for_card); } -bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) { - assert(r->in_collection_set(), "should only be called on elements of CS."); - uint region_idx = r->hrm_index(); +void G1ScanRSForRegionClosure::scan_card(MemRegion mr, uint region_idx_for_card) { + HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); + _scan_objs_on_card_cl->set_region(card_region); + card_region->oops_on_card_seq_iterate_careful(mr, _scan_objs_on_card_cl); + _scan_objs_on_card_cl->trim_queue_partially(); + _cards_scanned++; +} + +void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) { + uint const region_idx = r->hrm_index(); - if (_scan_state->iter_is_complete(region_idx)) { - return false; - } if (_scan_state->claim_iter(region_idx)) { // If we ever free the collection set concurrently, we should also // clear the card table concurrently therefore we won't need to @@ -397,33 +391,52 @@ bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) { scan_card(mr, region_idx_for_card); } +} + +void G1ScanRSForRegionClosure::scan_strong_code_roots(HeapRegion* r) { + r->strong_code_roots_do(_pss->closures()->weak_codeblobs()); +} + +bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) { + assert(r->in_collection_set(), + "Should only be called on elements of the collection set but region %u is not.", + r->hrm_index()); + uint const region_idx = r->hrm_index(); + + // Do an early out if we know we are complete. + if (_scan_state->iter_is_complete(region_idx)) { + return false; + } + + { + G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); + scan_rem_set_roots(r); + } + if (_scan_state->set_iter_complete(region_idx)) { + G1EvacPhaseWithTrimTimeTracker timer(_pss, _strong_code_root_scan_time, _strong_code_trim_partially_time); // Scan the strong code root list attached to the current region scan_strong_code_roots(r); } return false; } -void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, - CodeBlobClosure* heap_region_codeblobs, - uint worker_i) { - double rs_time_start = os::elapsedTime(); - +void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i) { G1ScanObjsDuringScanRSClosure scan_cl(_g1h, pss); - G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, heap_region_codeblobs, worker_i); + G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, worker_i); _g1h->collection_set_iterate_from(&cl, worker_i); - double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) - - cl.strong_code_root_scan_time_sec(); - G1GCPhaseTimes* p = _g1p->phase_times(); - p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, scan_rs_time_sec); + p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, TicksToTimeHelper::seconds(cl.rem_set_root_scan_time())); + p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.rem_set_trim_partially_time())); + p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards); p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards); p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards); - p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time_sec()); + p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_scan_time())); + p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_trim_partially_time())); } // Closure used for updating rem sets. Only called during an evacuation pause. @@ -448,6 +461,7 @@ public: bool card_scanned = _g1rs->refine_card_during_gc(card_ptr, _update_rs_cl); if (card_scanned) { + _update_rs_cl->trim_queue_partially(); _cards_scanned++; } else { _cards_skipped++; @@ -460,32 +474,37 @@ public: }; void G1RemSet::update_rem_set(G1ParScanThreadState* pss, uint worker_i) { - G1ScanObjsDuringUpdateRSClosure update_rs_cl(_g1h, pss, worker_i); - G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl); + G1GCPhaseTimes* p = _g1p->phase_times(); - G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); + // Apply closure to log entries in the HCC. if (G1HotCardCache::default_use_cache()) { - // Apply the closure to the entries of the hot card cache. - G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); + G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::ScanHCC, worker_i); + + G1ScanObjsDuringUpdateRSClosure scan_hcc_cl(_g1h, pss, worker_i); + G1RefineCardClosure refine_card_cl(_g1h, &scan_hcc_cl); _g1h->iterate_hcc_closure(&refine_card_cl, worker_i); } - // Apply the closure to all remaining log entries. - _g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i); - G1GCPhaseTimes* p = _g1p->phase_times(); - p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_scanned(), G1GCPhaseTimes::UpdateRSScannedCards); - p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_skipped(), G1GCPhaseTimes::UpdateRSSkippedCards); + // Now apply the closure to all remaining log entries. + { + G1EvacPhaseTimesTracker x(p, pss, G1GCPhaseTimes::UpdateRS, worker_i); + + G1ScanObjsDuringUpdateRSClosure update_rs_cl(_g1h, pss, worker_i); + G1RefineCardClosure refine_card_cl(_g1h, &update_rs_cl); + _g1h->iterate_dirty_card_closure(&refine_card_cl, worker_i); + + p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_scanned(), G1GCPhaseTimes::UpdateRSScannedCards); + p->record_thread_work_item(G1GCPhaseTimes::UpdateRS, worker_i, refine_card_cl.cards_skipped(), G1GCPhaseTimes::UpdateRSSkippedCards); + } } void G1RemSet::cleanupHRRS() { HeapRegionRemSet::cleanup(); } -void G1RemSet::oops_into_collection_set_do(G1ParScanThreadState* pss, - CodeBlobClosure* heap_region_codeblobs, - uint worker_i) { +void G1RemSet::oops_into_collection_set_do(G1ParScanThreadState* pss, uint worker_i) { update_rem_set(pss, worker_i); - scan_rem_set(pss, heap_region_codeblobs, worker_i);; + scan_rem_set(pss, worker_i);; } void G1RemSet::prepare_for_oops_into_collection_set_do() { diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index f816136c051..36b9a54e12d 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -32,6 +32,7 @@ #include "gc/g1/heapRegion.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" +#include "utilities/ticks.hpp" // A G1RemSet provides ways of iterating over pointers into a selected // collection set. @@ -61,9 +62,7 @@ private: // Scan all remembered sets of the collection set for references into the collection // set. - void scan_rem_set(G1ParScanThreadState* pss, - CodeBlobClosure* heap_region_codeblobs, - uint worker_i); + void scan_rem_set(G1ParScanThreadState* pss, uint worker_i); // Flush remaining refinement buffers for cross-region references to either evacuate references // into the collection set or update the remembered set. @@ -102,9 +101,7 @@ public: // // Further applies heap_region_codeblobs on the oops of the unmarked nmethods on the strong code // roots list for each region in the collection set. - void oops_into_collection_set_do(G1ParScanThreadState* pss, - CodeBlobClosure* heap_region_codeblobs, - uint worker_i); + void oops_into_collection_set_do(G1ParScanThreadState* pss, uint worker_i); // Prepare for and cleanup after an oops_into_collection_set_do // call. Must call each of these once before and after (in sequential @@ -138,37 +135,44 @@ public: }; class G1ScanRSForRegionClosure : public HeapRegionClosure { + G1CollectedHeap* _g1h; + G1CardTable *_ct; + + G1ParScanThreadState* _pss; + G1ScanObjsDuringScanRSClosure* _scan_objs_on_card_cl; + G1RemSetScanState* _scan_state; + uint _worker_i; + size_t _cards_scanned; size_t _cards_claimed; size_t _cards_skipped; - G1CollectedHeap* _g1h; + Tickspan _rem_set_root_scan_time; + Tickspan _rem_set_trim_partially_time; - G1ScanObjsDuringScanRSClosure* _scan_objs_on_card_cl; - CodeBlobClosure* _code_root_cl; - - G1BlockOffsetTable* _bot; - G1CardTable *_ct; - - double _strong_code_root_scan_time_sec; - uint _worker_i; + Tickspan _strong_code_root_scan_time; + Tickspan _strong_code_trim_partially_time; void claim_card(size_t card_index, const uint region_idx_for_card); void scan_card(MemRegion mr, uint region_idx_for_card); + + void scan_rem_set_roots(HeapRegion* r); void scan_strong_code_roots(HeapRegion* r); public: G1ScanRSForRegionClosure(G1RemSetScanState* scan_state, G1ScanObjsDuringScanRSClosure* scan_obj_on_card, - CodeBlobClosure* code_root_cl, + G1ParScanThreadState* pss, uint worker_i); bool do_heap_region(HeapRegion* r); - double strong_code_root_scan_time_sec() { - return _strong_code_root_scan_time_sec; - } + Tickspan rem_set_root_scan_time() const { return _rem_set_root_scan_time; } + Tickspan rem_set_trim_partially_time() const { return _rem_set_trim_partially_time; } + + Tickspan strong_code_root_scan_time() const { return _strong_code_root_scan_time; } + Tickspan strong_code_root_trim_partially_time() const { return _strong_code_trim_partially_time; } size_t cards_scanned() const { return _cards_scanned; } size_t cards_claimed() const { return _cards_claimed; } diff --git a/src/hotspot/share/gc/g1/g1RootClosures.cpp b/src/hotspot/share/gc/g1/g1RootClosures.cpp index 11e01682580..41f8c953242 100644 --- a/src/hotspot/share/gc/g1/g1RootClosures.cpp +++ b/src/hotspot/share/gc/g1/g1RootClosures.cpp @@ -37,8 +37,8 @@ public: bool in_young_gc) : _closures(g1h, pss, in_young_gc, /* must_claim_cld */ false) {} - OopClosure* weak_oops() { return &_closures._buffered_oops; } - OopClosure* strong_oops() { return &_closures._buffered_oops; } + OopClosure* weak_oops() { return &_closures._oops; } + OopClosure* strong_oops() { return &_closures._oops; } CLDClosure* weak_clds() { return &_closures._clds; } CLDClosure* strong_clds() { return &_closures._clds; } @@ -47,9 +47,6 @@ public: CodeBlobClosure* strong_codeblobs() { return &_closures._codeblobs; } CodeBlobClosure* weak_codeblobs() { return &_closures._codeblobs; } - void flush() { _closures._buffered_oops.done(); } - double closure_app_seconds() { return _closures._buffered_oops.closure_app_seconds(); } - OopClosure* raw_strong_oops() { return &_closures._oops; } bool trace_metadata() { return false; } @@ -79,8 +76,8 @@ public: _strong(g1h, pss, /* process_only_dirty_klasses */ false, /* must_claim_cld */ true), _weak(g1h, pss, /* process_only_dirty_klasses */ false, /* must_claim_cld */ true) {} - OopClosure* weak_oops() { return &_weak._buffered_oops; } - OopClosure* strong_oops() { return &_strong._buffered_oops; } + OopClosure* weak_oops() { return &_weak._oops; } + OopClosure* strong_oops() { return &_strong._oops; } // If MarkWeak is G1MarkPromotedFromRoot then the weak CLDs must be processed in a second pass. CLDClosure* weak_clds() { return null_if(&_weak._clds); } @@ -93,16 +90,6 @@ public: CodeBlobClosure* strong_codeblobs() { return &_strong._codeblobs; } CodeBlobClosure* weak_codeblobs() { return &_weak._codeblobs; } - void flush() { - _strong._buffered_oops.done(); - _weak._buffered_oops.done(); - } - - double closure_app_seconds() { - return _strong._buffered_oops.closure_app_seconds() + - _weak._buffered_oops.closure_app_seconds(); - } - OopClosure* raw_strong_oops() { return &_strong._oops; } // If we are not marking all weak roots then we are tracing diff --git a/src/hotspot/share/gc/g1/g1RootClosures.hpp b/src/hotspot/share/gc/g1/g1RootClosures.hpp index 2c648aa5727..cc86b1d7d62 100644 --- a/src/hotspot/share/gc/g1/g1RootClosures.hpp +++ b/src/hotspot/share/gc/g1/g1RootClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,10 +49,6 @@ public: class G1EvacuationRootClosures : public G1RootClosures { public: - // Flush any buffered state and deferred processing - virtual void flush() = 0; - virtual double closure_app_seconds() = 0; - // Applied to the weakly reachable CLDs when all strongly reachable // CLDs are guaranteed to have been processed. virtual CLDClosure* second_pass_weak_clds() = 0; diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.cpp b/src/hotspot/share/gc/g1/g1RootProcessor.cpp index 204414582ce..372cfb859b2 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp @@ -28,12 +28,12 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" -#include "gc/g1/bufferingOopClosure.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1CodeBlobClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" +#include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RootProcessor.hpp" @@ -73,10 +73,12 @@ G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) : _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never), _n_workers_discovered_strong_classes(0) {} -void G1RootProcessor::evacuate_roots(G1EvacuationRootClosures* closures, uint worker_i) { - double ext_roots_start = os::elapsedTime(); +void G1RootProcessor::evacuate_roots(G1ParScanThreadState* pss, uint worker_i) { G1GCPhaseTimes* phase_times = _g1h->g1_policy()->phase_times(); + G1EvacPhaseTimesTracker timer(phase_times, pss, G1GCPhaseTimes::ExtRootScan, worker_i); + + G1EvacuationRootClosures* closures = pss->closures(); process_java_roots(closures, phase_times, worker_i); // This is the point where this worker thread will not find more strong CLDs/nmethods. @@ -118,17 +120,6 @@ void G1RootProcessor::evacuate_roots(G1EvacuationRootClosures* closures, uint wo assert(closures->second_pass_weak_clds() == NULL, "Should be null if not tracing metadata."); } - // Finish up any enqueued closure apps (attributed as object copy time). - closures->flush(); - - double obj_copy_time_sec = closures->closure_app_seconds(); - - phase_times->record_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, obj_copy_time_sec); - - double ext_root_time_sec = os::elapsedTime() - ext_roots_start - obj_copy_time_sec; - - phase_times->record_time_secs(G1GCPhaseTimes::ExtRootScan, worker_i, ext_root_time_sec); - // During conc marking we have to filter the per-thread SATB buffers // to make sure we remove any oops into the CSet (which will show up // as implicitly live). diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.hpp b/src/hotspot/share/gc/g1/g1RootProcessor.hpp index f77e15c5ce6..c4b5f03016e 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ class CodeBlobClosure; class G1CollectedHeap; class G1EvacuationRootClosures; class G1GCPhaseTimes; +class G1ParScanThreadState; class G1RootClosures; class Monitor; class OopClosure; @@ -97,10 +98,10 @@ class G1RootProcessor : public StackObj { public: G1RootProcessor(G1CollectedHeap* g1h, uint n_workers); - // Apply closures to the strongly and weakly reachable roots in the system + // Apply correct closures from pss to the strongly and weakly reachable roots in the system // in a single pass. // Record and report timing measurements for sub phases using the worker_i - void evacuate_roots(G1EvacuationRootClosures* closures, uint worker_i); + void evacuate_roots(G1ParScanThreadState* pss, uint worker_id); // Apply oops, clds and blobs to all strongly reachable roots in the system void process_strong_roots(OopClosure* oops, diff --git a/src/hotspot/share/gc/g1/g1SharedClosures.hpp b/src/hotspot/share/gc/g1/g1SharedClosures.hpp index 98af60123b1..adb67b9ac98 100644 --- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp +++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp @@ -22,7 +22,6 @@ * */ -#include "gc/g1/bufferingOopClosure.hpp" #include "gc/g1/g1CodeBlobClosure.hpp" #include "gc/g1/g1OopClosures.hpp" #include "memory/iterator.hpp" @@ -39,12 +38,10 @@ public: G1CLDScanClosure _clds; G1CodeBlobClosure _codeblobs; - BufferingOopClosure _buffered_oops; G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty, bool must_claim_cld) : _oops(g1h, pss), _oops_in_cld(g1h, pss), _clds(&_oops_in_cld, process_only_dirty, must_claim_cld), - _codeblobs(&_oops), - _buffered_oops(&_oops) {} + _codeblobs(&_oops) {} }; diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp index ca0e1a02a58..b7edc47ea14 100644 --- a/src/hotspot/share/gc/shared/taskqueue.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -285,9 +285,10 @@ public: inline bool push(E t); // Attempts to claim a task from the "local" end of the queue (the most - // recently pushed). If successful, returns true and sets t to the task; - // otherwise, returns false (the queue is empty). - inline bool pop_local(volatile E& t); + // recently pushed) as long as the number of entries exceeds the threshold. + // If successful, returns true and sets t to the task; otherwise, returns false + // (the queue is empty or the number of elements below the threshold). + inline bool pop_local(volatile E& t, uint threshold = 0); // Like pop_local(), but uses the "global" end of the queue (the least // recently pushed). diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index ad172241d21..476098d57aa 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -152,7 +152,7 @@ bool GenericTaskQueue::pop_local_slow(uint localBot, Age oldAge) { } template inline bool -GenericTaskQueue::pop_local(volatile E& t) { +GenericTaskQueue::pop_local(volatile E& t, uint threshold) { uint localBot = _bottom; // This value cannot be N-1. That can only occur as a result of // the assignment to bottom in this method. If it does, this method @@ -160,7 +160,7 @@ GenericTaskQueue::pop_local(volatile E& t) { // since this is pop_local.) uint dirty_n_elems = dirty_size(localBot, _age.top()); assert(dirty_n_elems != N - 1, "Shouldn't be possible..."); - if (dirty_n_elems == 0) return false; + if (dirty_n_elems <= threshold) return false; localBot = decrement_index(localBot); _bottom = localBot; // This is necessary to prevent any read below from being reordered diff --git a/src/hotspot/share/utilities/ticks.hpp b/src/hotspot/share/utilities/ticks.hpp index 2bbb74ed3db..34ff1efd49c 100644 --- a/src/hotspot/share/utilities/ticks.hpp +++ b/src/hotspot/share/utilities/ticks.hpp @@ -47,6 +47,11 @@ class Tickspan { return *this; } + Tickspan& operator-=(const Tickspan& rhs) { + _span_ticks -= rhs._span_ticks; + return *this; + } + jlong value() const { return _span_ticks; } diff --git a/src/hotspot/share/utilities/ticks.inline.hpp b/src/hotspot/share/utilities/ticks.inline.hpp index 7929cea1693..3d031977fa6 100644 --- a/src/hotspot/share/utilities/ticks.inline.hpp +++ b/src/hotspot/share/utilities/ticks.inline.hpp @@ -32,6 +32,11 @@ inline Tickspan operator+(Tickspan lhs, const Tickspan& rhs) { return lhs; } +inline Tickspan operator-(Tickspan lhs, const Tickspan& rhs) { + lhs -= rhs; + return lhs; +} + inline bool operator==(const Tickspan& lhs, const Tickspan& rhs) { return lhs.value() == rhs.value(); } diff --git a/test/hotspot/gtest/gc/g1/test_bufferingOopClosure.cpp b/test/hotspot/gtest/gc/g1/test_bufferingOopClosure.cpp deleted file mode 100644 index 1bc51188660..00000000000 --- a/test/hotspot/gtest/gc/g1/test_bufferingOopClosure.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 "gc/g1/bufferingOopClosure.hpp" -#include "memory/iterator.hpp" -#include "unittest.hpp" - -class BufferingOopClosureTest : public ::testing::Test { - public: - // Helper class to fake a set of oop*s and narrowOop*s. - class FakeRoots { - public: - // Used for sanity checking of the values passed to the do_oops functions in the test. - static const uintptr_t NarrowOopMarker = uintptr_t(1) << (BitsPerWord -1); - - int _num_narrow; - int _num_full; - void** _narrow; - void** _full; - - FakeRoots(int num_narrow, int num_full) : - _num_narrow(num_narrow), - _num_full(num_full), - _narrow((void**)::malloc(sizeof(void*) * num_narrow)), - _full((void**)::malloc(sizeof(void*) * num_full)) { - - for (int i = 0; i < num_narrow; i++) { - _narrow[i] = (void*)(NarrowOopMarker + (uintptr_t)i); - } - for (int i = 0; i < num_full; i++) { - _full[i] = (void*)(uintptr_t)i; - } - } - - ~FakeRoots() { - ::free(_narrow); - ::free(_full); - } - - void oops_do_narrow_then_full(OopClosure* cl) { - for (int i = 0; i < _num_narrow; i++) { - cl->do_oop((narrowOop*)_narrow[i]); - } - for (int i = 0; i < _num_full; i++) { - cl->do_oop((oop*)_full[i]); - } - } - - void oops_do_full_then_narrow(OopClosure* cl) { - for (int i = 0; i < _num_full; i++) { - cl->do_oop((oop*)_full[i]); - } - for (int i = 0; i < _num_narrow; i++) { - cl->do_oop((narrowOop*)_narrow[i]); - } - } - - void oops_do_mixed(OopClosure* cl) { - int i; - for (i = 0; i < _num_full && i < _num_narrow; i++) { - cl->do_oop((oop*)_full[i]); - cl->do_oop((narrowOop*)_narrow[i]); - } - for (int j = i; j < _num_full; j++) { - cl->do_oop((oop*)_full[i]); - } - for (int j = i; j < _num_narrow; j++) { - cl->do_oop((narrowOop*)_narrow[i]); - } - } - - static const int MaxOrder = 2; - - void oops_do(OopClosure* cl, int do_oop_order) { - switch(do_oop_order) { - case 0: - oops_do_narrow_then_full(cl); - break; - case 1: - oops_do_full_then_narrow(cl); - break; - case 2: - oops_do_mixed(cl); - break; - default: - oops_do_narrow_then_full(cl); - break; - } - } - }; - - class CountOopClosure : public OopClosure { - int _narrow_oop_count; - int _full_oop_count; - public: - CountOopClosure() : _narrow_oop_count(0), _full_oop_count(0) {} - void do_oop(narrowOop* p) { - EXPECT_NE(uintptr_t(0), (uintptr_t(p) & FakeRoots::NarrowOopMarker)) - << "The narrowOop was unexpectedly not marked with the NarrowOopMarker"; - _narrow_oop_count++; - } - - void do_oop(oop* p){ - EXPECT_EQ(uintptr_t(0), (uintptr_t(p) & FakeRoots::NarrowOopMarker)) - << "The oop was unexpectedly marked with the NarrowOopMarker"; - _full_oop_count++; - } - - int narrow_oop_count() { return _narrow_oop_count; } - int full_oop_count() { return _full_oop_count; } - int all_oop_count() { return _narrow_oop_count + _full_oop_count; } - }; - - class DoNothingOopClosure : public OopClosure { - public: - void do_oop(narrowOop* p) {} - void do_oop(oop* p) {} - }; - - static void testCount(int num_narrow, int num_full, int do_oop_order) { - FakeRoots fr(num_narrow, num_full); - - CountOopClosure coc; - BufferingOopClosure boc(&coc); - - fr.oops_do(&boc, do_oop_order); - - boc.done(); - - EXPECT_EQ(num_narrow, coc.narrow_oop_count()) << "when running testCount(" - << num_narrow << ", " << num_full << ", " << do_oop_order << ")"; - - EXPECT_EQ(num_full, coc.full_oop_count()) << "when running testCount(" - << num_narrow << ", " << num_full << ", " << do_oop_order << ")"; - - EXPECT_EQ(num_narrow + num_full, coc.all_oop_count()) << "when running testCount(" - << num_narrow << ", " << num_full << ", " << do_oop_order << ")"; - } - - static void testIsBufferEmptyOrFull(int num_narrow, int num_full, bool expect_empty, bool expect_full) { - FakeRoots fr(num_narrow, num_full); - - DoNothingOopClosure cl; - BufferingOopClosure boc(&cl); - - fr.oops_do(&boc, 0); - - EXPECT_EQ(expect_empty, boc.is_buffer_empty()) - << "when running testIsBufferEmptyOrFull(" - << num_narrow << ", " << num_full << ", " - << expect_empty << ", " << expect_full << ")"; - - EXPECT_EQ(expect_full, boc.is_buffer_full()) - << "when running testIsBufferEmptyOrFull(" - << num_narrow << ", " << num_full << ", " - << expect_empty << ", " << expect_full << ")"; - } - - static void testEmptyAfterDone(int num_narrow, int num_full) { - FakeRoots fr(num_narrow, num_full); - - DoNothingOopClosure cl; - BufferingOopClosure boc(&cl); - - fr.oops_do(&boc, 0); - - // Make sure all get processed. - boc.done(); - - EXPECT_TRUE(boc.is_buffer_empty()) << "Should be empty after call to done()." - << " testEmptyAfterDone(" << num_narrow << ", " << num_full << ")"; - } - - static int get_buffer_length() { - return BufferingOopClosure::BufferLength; - } -}; - -TEST_VM_F(BufferingOopClosureTest, count_test) { - int bl = BufferingOopClosureTest::get_buffer_length(); - - for (int order = 0; order < FakeRoots::MaxOrder; order++) { - testCount(0, 0, order); - testCount(10, 0, order); - testCount(0, 10, order); - testCount(10, 10, order); - testCount(bl, 10, order); - testCount(10, bl, order); - testCount(bl, bl, order); - testCount(bl + 1, 10, order); - testCount(10, bl + 1, order); - testCount(bl + 1, bl, order); - testCount(bl, bl + 1, order); - testCount(bl + 1, bl + 1, order); - } -} - -TEST_VM_F(BufferingOopClosureTest, buffer_empty_or_full) { - int bl = BufferingOopClosureTest::get_buffer_length(); - - testIsBufferEmptyOrFull(0, 0, true, false); - testIsBufferEmptyOrFull(1, 0, false, false); - testIsBufferEmptyOrFull(0, 1, false, false); - testIsBufferEmptyOrFull(1, 1, false, false); - testIsBufferEmptyOrFull(10, 0, false, false); - testIsBufferEmptyOrFull(0, 10, false, false); - testIsBufferEmptyOrFull(10, 10, false, false); - testIsBufferEmptyOrFull(0, bl, false, true); - testIsBufferEmptyOrFull(bl, 0, false, true); - testIsBufferEmptyOrFull(bl / 2, bl / 2, false, true); - testIsBufferEmptyOrFull(bl - 1, 1, false, true); - testIsBufferEmptyOrFull(1, bl - 1, false, true); - // Processed - testIsBufferEmptyOrFull(bl + 1, 0, false, false); - testIsBufferEmptyOrFull(bl * 2, 0, false, true); -} - -TEST_VM_F(BufferingOopClosureTest, empty_after_done) { - int bl = BufferingOopClosureTest::get_buffer_length(); - - testEmptyAfterDone(0, 0); - testEmptyAfterDone(1, 0); - testEmptyAfterDone(0, 1); - testEmptyAfterDone(1, 1); - testEmptyAfterDone(10, 0); - testEmptyAfterDone(0, 10); - testEmptyAfterDone(10, 10); - testEmptyAfterDone(0, bl); - testEmptyAfterDone(bl, 0); - testEmptyAfterDone(bl / 2, bl / 2); - testEmptyAfterDone(bl - 1, 1); - testEmptyAfterDone(1, bl - 1); - // Processed - testEmptyAfterDone(bl + 1, 0); - testEmptyAfterDone(bl * 2, 0); -} From d24f8fd099347fcce37849479ca02e16ec26d338 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Fri, 27 Apr 2018 13:09:54 +0100 Subject: [PATCH 067/102] 8202367: AIX build broken after JDK-8201543 Reviewed-by: eosterlund, shade, mdoerr --- src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp index f63638283ce..84815adea80 100644 --- a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/c1/cardTableBarrierSetC1.hpp" +#include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "utilities/macros.hpp" From f236cf3cf43cec853a3c8576814c14a11241c33c Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Fri, 27 Apr 2018 08:45:11 -0400 Subject: [PATCH 068/102] 8202204: Rename hotspot runtime jtreg constantPool ConstantPool directories Move the tests in the constantPool directory to a new directory named AccModule. Reviewed-by: dholmes, gtriantafill --- .../jtreg/runtime/{constantPool => AccModule}/ACCModule52.java | 2 +- .../jtreg/runtime/{constantPool => AccModule}/ConstModule.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename test/hotspot/jtreg/runtime/{constantPool => AccModule}/ACCModule52.java (96%) rename test/hotspot/jtreg/runtime/{constantPool => AccModule}/ConstModule.java (99%) diff --git a/test/hotspot/jtreg/runtime/constantPool/ACCModule52.java b/test/hotspot/jtreg/runtime/AccModule/ACCModule52.java similarity index 96% rename from test/hotspot/jtreg/runtime/constantPool/ACCModule52.java rename to test/hotspot/jtreg/runtime/AccModule/ACCModule52.java index 241425076ca..3af0c146089 100644 --- a/test/hotspot/jtreg/runtime/constantPool/ACCModule52.java +++ b/test/hotspot/jtreg/runtime/AccModule/ACCModule52.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/hotspot/jtreg/runtime/constantPool/ConstModule.java b/test/hotspot/jtreg/runtime/AccModule/ConstModule.java similarity index 99% rename from test/hotspot/jtreg/runtime/constantPool/ConstModule.java rename to test/hotspot/jtreg/runtime/AccModule/ConstModule.java index 27d9c2008b9..bff5ec67e0a 100644 --- a/test/hotspot/jtreg/runtime/constantPool/ConstModule.java +++ b/test/hotspot/jtreg/runtime/AccModule/ConstModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From a79484396d8753bfa677426945c6cfac536a9c8c Mon Sep 17 00:00:00 2001 From: Martin Balao Date: Wed, 25 Apr 2018 12:21:29 -0400 Subject: [PATCH 069/102] 8201509: Zero: S390 31bit atomic_copy64 inline assembler is wrong The inline assembler for the S390 (S390 and not _LP64) has src and dst reversed thereby corrupting data Reviewed-by: shade --- src/hotspot/os_cpu/linux_zero/os_linux_zero.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.hpp index a36e4792efd..a018b6114d4 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007, 2008, 2010 Red Hat, Inc. + * Copyright 2007, 2008, 2010, 2018, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,10 +50,10 @@ : "Q"(*(volatile long*)src)); #elif defined(S390) && !defined(_LP64) double tmp; - asm volatile ("ld %0, 0(%1)\n" - "std %0, 0(%2)\n" - : "=r"(tmp) - : "a"(src), "a"(dst)); + asm volatile ("ld %0, %2\n" + "std %0, %1\n" + : "=&f"(tmp), "=Q"(*(volatile double*)dst) + : "Q"(*(volatile double*)src)); #else *(jlong *) dst = *(const jlong *) src; #endif From 1b027ddfe912e73f4d2dff94032a8f9babb4160b Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 27 Apr 2018 08:28:06 -0700 Subject: [PATCH 070/102] 8202273: [AOT] Graal does not support the CMS collector Avoid running AOT and JVMCI tests with CMS Reviewed-by: dcubed --- test/hotspot/jtreg/TEST.groups | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 19c5262a97c..1ab2d17b912 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -35,6 +35,10 @@ hotspot_compiler_xcomp = \ :hotspot_compiler \ -:tier1_compiler_not_xcomp +hotspot_compiler_all_gcs = \ + :hotspot_compiler \ + -:tier1_compiler_not_cms + hotspot_gc = \ gc @@ -135,6 +139,10 @@ tier1_compiler_3 = \ tier1_compiler_not_xcomp = \ compiler/aot +tier1_compiler_not_cms = \ + compiler/aot \ + compiler/jvmci + ctw_1 = \ applications/ctw/modules/ \ -:ctw_2 \ From 25a8a3ad660bf30c6afa302070eac88e689046cb Mon Sep 17 00:00:00 2001 From: Archana Nogriya Date: Fri, 27 Apr 2018 09:57:16 -0700 Subject: [PATCH 071/102] 8202382: Filter docs modules Reviewed-by: erikj --- make/Docs.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/Docs.gmk b/make/Docs.gmk index 487f0500d3a..cd611e654cb 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -429,7 +429,7 @@ ifneq ($(findstring javafx., $(IMPORTED_MODULES)), ) endif # All modules to have docs generated by docs-jdk-api target -JDK_MODULES := $(sort $(DOCS_MODULES)) +JDK_MODULES := $(sort $(filter-out $(MODULES_FILTER), $(DOCS_MODULES))) $(eval $(call SetupApiDocsGeneration, JDK_API, \ MODULES := $(JDK_MODULES), \ From 9037ee0ef15e7a91dcc2a2778d8ceaeb8ec1190f Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 27 Apr 2018 15:55:29 -0700 Subject: [PATCH 072/102] 8201622: Reduce unnecessary Package.complete() calls in javadoc Reviewed-by: jlahoda --- .../sun/tools/javac/model/JavacElements.java | 15 +++++++------ .../internal/doclets/toolkit/WorkArounds.java | 22 ++++++++++++++----- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index 9db8f3cb751..35ee43c40fc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -247,14 +247,15 @@ public class JavacElements implements Elements { if (sym == null) sym = javaCompiler.resolveIdent(module, nameStr); - sym.complete(); - - return (sym.kind != ERR && + if (clazz.isInstance(sym)) { + sym.complete(); + if (sym.kind != ERR && sym.exists() && - clazz.isInstance(sym) && - name.equals(sym.getQualifiedName())) - ? clazz.cast(sym) - : null; + name.equals(sym.getQualifiedName())) { + return clazz.cast(sym); + } + } + return null; } catch (CompletionFailure cf) { cf.dcfh.handleAPICompletionFailure(cf); return null; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java index c2708e9d6a3..19a9cc6457d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package jdk.javadoc.internal.doclets.toolkit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -200,10 +199,15 @@ public class WorkArounds { // TODO: needs to ported to jx.l.m. public TypeElement searchClass(TypeElement klass, String className) { - // search by qualified name first - TypeElement te = configuration.docEnv.getElementUtils().getTypeElement(className); - if (te != null) { - return te; + TypeElement te; + + // search by qualified name in current module first + ModuleElement me = utils.containingModule(klass); + if (me != null) { + te = configuration.docEnv.getElementUtils().getTypeElement(me, className); + if (te != null) { + return te; + } } // search inner classes @@ -251,6 +255,12 @@ public class WorkArounds { } } + // finally, search by qualified name in all modules + te = configuration.docEnv.getElementUtils().getTypeElement(className); + if (te != null) { + return te; + } + return null; // not found } From a01b2f3b734933087daa29c7e78b6bb15a43d375 Mon Sep 17 00:00:00 2001 From: Rachna Goel Date: Mon, 30 Apr 2018 11:59:42 +0530 Subject: [PATCH 073/102] 8179071: Month value is inconsistent between CLDR and Java in some locales Handled Language aliases from CLDR SupplementalMetaData Reviewed-by: naoto --- .../tools/cldrconverter/CLDRConverter.java | 4 +- .../ResourceBundleGenerator.java | 24 ++++- .../SupplementalMetadataParseHandler.java | 28 ++++++ .../util/cldr/CLDRLocaleProviderAdapter.java | 24 ++++- .../locale/provider/LocaleDataMetaInfo.java | 11 ++- test/jdk/java/util/Locale/Bug8179071.java | 93 +++++++++++++++++++ test/jdk/sun/text/resources/LocaleData.cldr | 8 +- .../sun/text/resources/LocaleDataTest.java | 2 +- .../plugins/IncludeLocalesPluginTest.java | 4 +- 9 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 test/jdk/java/util/Locale/Bug8179071.java diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 40ba06a6349..fd621a9e9cc 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -90,8 +90,8 @@ public class CLDRConverter { static final String[] EMPTY_ZONE = {"", "", "", "", "", ""}; private static SupplementDataParseHandler handlerSuppl; - private static SupplementalMetadataParseHandler handlerSupplMeta; private static LikelySubtagsParseHandler handlerLikelySubtags; + static SupplementalMetadataParseHandler handlerSupplMeta; static NumberingSystemsParseHandler handlerNumbering; static MetaZonesParseHandler handlerMetaZones; static TimeZoneParseHandler handlerTimeZone; @@ -428,7 +428,7 @@ public class CLDRConverter { parseLDMLFile(new File(LIKELYSUBTAGS_SOURCE_FILE), handlerLikelySubtags); // Parse supplementalMetadata - // Currently only interested in deprecated time zone ids. + // Currently interested in deprecated time zone ids and language aliases. handlerSupplMeta = new SupplementalMetadataParseHandler(); parseLDMLFile(new File(SPPL_META_SOURCE_FILE), handlerSupplMeta); } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 9df469fdc5d..edfcca3e30b 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -270,7 +270,8 @@ class ResourceBundleGenerator implements BundleGenerator { out.printf("public class %s implements LocaleDataMetaInfo {\n", className); out.printf(" private static final Map resourceNameToLocales = new HashMap<>();\n" + (CLDRConverter.isBaseModule ? - " private static final Map parentLocalesMap = new HashMap<>();\n\n" : + " private static final Map parentLocalesMap = new HashMap<>();\n" + + " private static final Map languageAliasMap = new HashMap<>();\n\n" : "\n") + " static {\n"); @@ -301,10 +302,16 @@ class ResourceBundleGenerator implements BundleGenerator { } else { if ("AvailableLocales".equals(key)) { out.printf(" resourceNameToLocales.put(\"%s\",\n", key); - out.printf(" \"%s\");\n", toLocaleList(metaInfo.get(key), false)); + out.printf(" \"%s\");\n", toLocaleList(applyLanguageAliases(metaInfo.get(key)), false)); } } } + // for languageAliasMap + if (CLDRConverter.isBaseModule) { + CLDRConverter.handlerSupplMeta.getLanguageAliasData().forEach((key, value) -> { + out.printf(" languageAliasMap.put(\"%s\", \"%s\");\n", key, value); + }); + } out.printf(" }\n\n"); @@ -339,6 +346,10 @@ class ResourceBundleGenerator implements BundleGenerator { " }\n\n"); if (CLDRConverter.isBaseModule) { + out.printf(" @Override\n" + + " public Map getLanguageAliasMap() {\n" + + " return languageAliasMap;\n" + + " }\n\n"); out.printf(" @Override\n" + " public Map tzCanonicalIDs() {\n" + " return TZCanonicalIDMapHolder.tzCanonicalIDMap;\n" + @@ -377,4 +388,13 @@ class ResourceBundleGenerator implements BundleGenerator { } return sb.toString(); } + + private static SortedSet applyLanguageAliases(SortedSet tags) { + CLDRConverter.handlerSupplMeta.getLanguageAliasData().forEach((key, value) -> { + if (tags.remove(key)) { + tags.add(value); + } + }); + return tags; + } } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java index 81149267ee9..43016f424c6 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java @@ -27,6 +27,8 @@ package build.tools.cldrconverter; import java.io.File; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Stream; import org.xml.sax.Attributes; import org.xml.sax.InputSource; @@ -38,6 +40,12 @@ import org.xml.sax.SAXException; */ class SupplementalMetadataParseHandler extends AbstractLDMLHandler { + private final Map languageAliasMap; + + SupplementalMetadataParseHandler() { + languageAliasMap = new HashMap<>(); + } + @Override public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException { // avoid HTTP traffic to unicode.org @@ -57,6 +65,17 @@ class SupplementalMetadataParseHandler extends AbstractLDMLHandler { } pushIgnoredContainer(qName); break; + case "languageAlias": + String aliasReason = attributes.getValue("reason"); + if ("deprecated".equals(aliasReason) || "legacy".equals(aliasReason)) { + String tag = attributes.getValue("type"); + if (!checkLegacyLocales(tag)) { + languageAliasMap.put(tag.replaceAll("_", "-"), + attributes.getValue("replacement").replaceAll("_", "-")); + } + } + pushIgnoredContainer(qName); + break; default: // treat anything else as a container pushContainer(qName, attributes); @@ -69,4 +88,13 @@ class SupplementalMetadataParseHandler extends AbstractLDMLHandler { .map(k -> String.format(" \"%s\", \"%s\",", k, get(k))) .sorted(); } + Map getLanguageAliasData() { + return languageAliasMap; + } + + // skip language aliases for JDK legacy locales for ISO compatibility + private boolean checkLegacyLocales(String tag) { + return (tag.startsWith("no") || tag.startsWith("in") + || tag.startsWith("iw") || tag.startsWith("ji")); + } } diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 92cf6c0d183..b9d0110ae39 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -64,8 +64,14 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { // parent locales map private static volatile Map parentLocalesMap; + // language aliases map + private static volatile Map langAliasesMap; + // cache to hold locale to locale mapping for language aliases. + private static final Map langAliasesCache; static { parentLocalesMap = new ConcurrentHashMap<>(); + langAliasesMap = new ConcurrentHashMap<>(); + langAliasesCache = new ConcurrentHashMap<>(); // Assuming these locales do NOT have irregular parent locales. parentLocalesMap.put(Locale.ROOT, Locale.ROOT); parentLocalesMap.put(Locale.ENGLISH, Locale.ENGLISH); @@ -160,6 +166,22 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { return locs; } + private Locale applyAliases(Locale loc) { + if (langAliasesMap.isEmpty()) { + langAliasesMap = baseMetaInfo.getLanguageAliasMap(); + } + Locale locale = langAliasesCache.get(loc); + if (locale == null) { + String locTag = loc.toLanguageTag(); + Locale aliasLocale = langAliasesMap.containsKey(locTag) + ? Locale.forLanguageTag(langAliasesMap.get(locTag)) : loc; + langAliasesCache.putIfAbsent(loc, aliasLocale); + return aliasLocale; + } else { + return locale; + } + } + @Override protected Set createLanguageTagSet(String category) { // Assume all categories support the same set as AvailableLocales @@ -194,7 +216,7 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { // Implementation of ResourceBundleBasedAdapter @Override public List getCandidateLocales(String baseName, Locale locale) { - List candidates = super.getCandidateLocales(baseName, locale); + List candidates = super.getCandidateLocales(baseName, applyAliases(locale)); return applyParentLocales(baseName, candidates); } diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java index a42b8dda7b5..28bcefc44e8 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,4 +58,13 @@ public interface LocaleDataMetaInfo { default public Map tzCanonicalIDs() { return null; } + + /** + * Returns a map for language aliases which specifies mapping from source language + * to from which it should be replaced. + * @return map of source language to replacement language, separated by a space. + */ + default public Map getLanguageAliasMap(){ + return null; + } } diff --git a/test/jdk/java/util/Locale/Bug8179071.java b/test/jdk/java/util/Locale/Bug8179071.java new file mode 100644 index 00000000000..b43336158bc --- /dev/null +++ b/test/jdk/java/util/Locale/Bug8179071.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 8179071 + * @summary Test that language aliases of CLDR supplemental metadata are handled correctly. + * @modules jdk.localedata + * @run main/othervm -Djava.locale.providers=CLDR Bug8179071 + */ + +/** + * This fix is dependent on a particular version of CLDR data. + */ + +import java.time.Month; +import java.time.format.TextStyle; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +public class Bug8179071 { + + // Deprecated and Legacy tags. + private static final Set LegacyAliases = Set.of("pa-PK", "ug-Arab-CN", "kk-Cyrl-KZ", + "bs-BA", "ks-Arab-IN", "mn-Cyrl-MN", "ha-Latn-NE", + "shi-MA", "ha-Latn-NG", "ms-Latn-BN","ms-Latn-SG", + "ky-Cyrl-KG", "az-AZ", "zh-guoyu", "zh-min-nan", "i-klingon", "i-tsu", + "sr-XK", "sgn-CH-DE", "mo", "i-tay", "scc", "uz-UZ", "uz-AF", "sr-RS", + "i-hak", "sgn-BE-FR", "i-lux", "vai-LR", "tl", "zh-hakka", "i-ami", "aa-SAAHO", "ha-Latn-GH", + "zh-xiang", "i-pwn", "sgn-BE-NL", "jw", "sh", "tzm-Latn-MA", "i-bnn"); + // expected month format data for locales after language aliases replacement. + private static Map shortJanuaryNames = Map.of( "pa-PK", "\u062c\u0646\u0648\u0631\u06cc", + "uz-AF" , "\u062c\u0646\u0648", + "sr-ME", "jan", + "scc", "\u0458\u0430\u043d", + "sh", "jan", + "ha-Latn-NE", "Jan", + "i-lux", "Jan."); + + + private static void test(String tag, String expected) { + Locale target = Locale.forLanguageTag(tag); + Month day = Month.JANUARY; + TextStyle style = TextStyle.SHORT; + String actual = day.getDisplayName(style, target); + if (!actual.equals(expected)) { + throw new RuntimeException("failed for locale " + tag + " actual output " + actual +" does not match with " + expected); + } + } + + /** + * getAvailableLocales() should not contain any deprecated or Legacy language tags + */ + private static void checkInvalidTags() { + Set invalidTags = new HashSet<>(); + Arrays.asList(Locale.getAvailableLocales()).stream() + .map(loc -> loc.toLanguageTag()) + .forEach( tag -> {if(LegacyAliases.contains(tag)) {invalidTags.add(tag);}}); + if (!invalidTags.isEmpty()) { + throw new RuntimeException("failed: Deprecated and Legacy tags found " + invalidTags + " in AvailableLocales "); + } + } + + public static void main(String[] args) { + shortJanuaryNames.forEach((key, value) -> test(key, value)); + checkInvalidTags(); + } +} diff --git a/test/jdk/sun/text/resources/LocaleData.cldr b/test/jdk/sun/text/resources/LocaleData.cldr index 8659cbc660e..dbec2176f29 100644 --- a/test/jdk/sun/text/resources/LocaleData.cldr +++ b/test/jdk/sun/text/resources/LocaleData.cldr @@ -5419,10 +5419,10 @@ FormatData/sr_BA/MonthNames/5=\u0458\u0443\u043d FormatData/sr_BA/MonthNames/6=\u0458\u0443\u043b FormatData/sr_BA/DayNames/3=\u0441\u0440\u0435\u0434\u0430 FormatData/sr_BA/DayAbbreviations/3=\u0441\u0440\u0435 -FormatData/sr_BA/TimePatterns/0=HH.mm.ss zzzz -FormatData/sr_BA/TimePatterns/1=HH.mm.ss z -FormatData/sr_BA/TimePatterns/2=HH.mm.ss -FormatData/sr_BA/TimePatterns/3=HH.mm +FormatData/sr_BA/TimePatterns/0=HH:mm:ss zzzz +FormatData/sr_BA/TimePatterns/1=HH:mm:ss z +FormatData/sr_BA/TimePatterns/2=HH:mm:ss +FormatData/sr_BA/TimePatterns/3=HH:mm FormatData/sr_BA/DatePatterns/0=EEEE, dd. MMMM y. FormatData/sr_BA/DatePatterns/1=dd. MMMM y. FormatData/sr_BA/DatePatterns/2=dd.MM.y. diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index a2ddaa0cc7f..44df3d317b9 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -38,7 +38,7 @@ * 7114053 7074882 7040556 8008577 8013836 8021121 6192407 6931564 8027695 * 8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361 8134916 * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 - * 8187946 8195478 8181157 + * 8187946 8195478 8181157 8179071 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata diff --git a/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java b/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java index 66f19224d40..cd32128757a 100644 --- a/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java +++ b/test/jdk/tools/jlink/plugins/IncludeLocalesPluginTest.java @@ -40,7 +40,7 @@ import tests.Result; /* * @test - * @bug 8152143 8152704 8155649 8165804 8185841 8176841 8190918 + * @bug 8152143 8152704 8155649 8165804 8185841 8176841 8190918 8179071 * @summary IncludeLocalesPlugin tests * @author Naoto Sato * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) @@ -256,7 +256,7 @@ public class IncludeLocalesPluginTest { "(root)", "as_IN", "as", "bn_IN", "bn", "bo_IN", "bo", "brx_IN", "brx", "en", "en_001", "en_IN", "en_US", "en_US_POSIX", "gu_IN", "gu", "hi_IN", "hi", "kn_IN", "kn", "kok_IN", "kok", "ks_IN", "ks", "ml_IN", "ml", - "mr_IN", "mr", "ne_IN", "ne", "or_IN", "or", "pa_IN", "pa", "pa_IN_#Guru", + "mr_IN", "mr", "ne_IN", "ne", "or_IN", "or", "pa", "pa_IN_#Guru", "pa__#Guru", "ta_IN", "ta", "te_IN", "te", "ur_IN", "ur"), "", }, From 55725ec33ce48bf167e2886f622a6a7fb3d834bd Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 30 Apr 2018 09:15:44 +0200 Subject: [PATCH 074/102] 8201650: Move iteration order randomization of unmodifiable Set and Map to iterators Reviewed-by: smarks, jiangli --- .../java/util/ImmutableCollections.java | 167 +++++++++++------- 1 file changed, 105 insertions(+), 62 deletions(-) diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 4ed5a467b9d..f0f289aca27 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -288,7 +288,7 @@ class ImmutableCollections { * Constructs a sublist of another SubList. */ static SubList fromSubList(SubList parent, int fromIndex, int toIndex) { - return new SubList(parent.root, parent.offset + fromIndex, toIndex - fromIndex); + return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex); } /** @@ -296,7 +296,7 @@ class ImmutableCollections { * not a SubList itself. */ static SubList fromList(List list, int fromIndex, int toIndex) { - return new SubList(list, fromIndex, toIndex - fromIndex); + return new SubList<>(list, fromIndex, toIndex - fromIndex); } public E get(int index) { @@ -309,12 +309,12 @@ class ImmutableCollections { } public Iterator iterator() { - return new ListItr(this, size()); + return new ListItr<>(this, size()); } public ListIterator listIterator(int index) { rangeCheck(index); - return new ListItr(this, size(), index); + return new ListItr<>(this, size(), index); } public List subList(int fromIndex, int toIndex) { @@ -472,13 +472,8 @@ class ImmutableCollections { throw new IllegalArgumentException("duplicate element: " + e0); } - if (SALT >= 0) { - this.e0 = e0; - this.e1 = e1; - } else { - this.e0 = e1; - this.e1 = e0; - } + this.e0 = e0; + this.e1 = e1; } @Override @@ -510,10 +505,10 @@ class ImmutableCollections { public E next() { if (idx == 1) { idx = 0; - return e0; + return SALT >= 0 || e1 == null ? e0 : e1; } else if (idx == 2) { idx = 1; - return e1; + return SALT >= 0 ? e1 : e0; } else { throw new NoSuchElementException(); } @@ -578,29 +573,55 @@ class ImmutableCollections { return size > 0 && probe(o) >= 0; } + private final class SetNIterator implements Iterator { + + private int remaining; + + private int idx; + + SetNIterator() { + remaining = size(); + if (remaining > 0) { + idx = Math.floorMod(SALT, elements.length); + } + } + + @Override + public boolean hasNext() { + return remaining > 0; + } + + private int nextIndex() { + int idx = this.idx; + if (SALT >= 0) { + if (++idx >= elements.length) { + idx = 0; + } + } else { + if (--idx < 0) { + idx = elements.length - 1; + } + } + return this.idx = idx; + } + + @Override + public E next() { + if (hasNext()) { + E element; + // skip null elements + while ((element = elements[nextIndex()]) == null) {} + remaining--; + return element; + } else { + throw new NoSuchElementException(); + } + } + } + @Override public Iterator iterator() { - return new Iterator<>() { - private int idx = 0; - - @Override - public boolean hasNext() { - while (idx < elements.length) { - if (elements[idx] != null) - return true; - idx++; - } - return false; - } - - @Override - public E next() { - if (! hasNext()) { - throw new NoSuchElementException(); - } - return elements[idx++]; - } - }; + return new SetNIterator(); } @Override @@ -619,7 +640,7 @@ class ImmutableCollections { // Callers are relying on this method to perform an implicit nullcheck // of pe private int probe(Object pe) { - int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length); + int idx = Math.floorMod(pe.hashCode(), elements.length); while (true) { E ee = elements[idx]; if (ee == null) { @@ -806,6 +827,53 @@ class ImmutableCollections { return size; } + class MapNIterator implements Iterator> { + + private int remaining; + + private int idx; + + MapNIterator() { + remaining = size(); + if (remaining > 0) { + idx = Math.floorMod(SALT, table.length >> 1) << 1; + } + } + + @Override + public boolean hasNext() { + return remaining > 0; + } + + private int nextIndex() { + int idx = this.idx; + if (SALT >= 0) { + if ((idx += 2) >= table.length) { + idx = 0; + } + } else { + if ((idx -= 2) < 0) { + idx = table.length - 2; + } + } + return this.idx = idx; + } + + @Override + public Map.Entry next() { + if (hasNext()) { + while (table[nextIndex()] == null) {} + @SuppressWarnings("unchecked") + Map.Entry e = + new KeyValueHolder<>((K)table[idx], (V)table[idx+1]); + remaining--; + return e; + } else { + throw new NoSuchElementException(); + } + } + } + @Override public Set> entrySet() { return new AbstractSet<>() { @@ -816,32 +884,7 @@ class ImmutableCollections { @Override public Iterator> iterator() { - return new Iterator<>() { - int idx = 0; - - @Override - public boolean hasNext() { - while (idx < table.length) { - if (table[idx] != null) - return true; - idx += 2; - } - return false; - } - - @Override - public Map.Entry next() { - if (hasNext()) { - @SuppressWarnings("unchecked") - Map.Entry e = - new KeyValueHolder<>((K)table[idx], (V)table[idx+1]); - idx += 2; - return e; - } else { - throw new NoSuchElementException(); - } - } - }; + return new MapNIterator(); } }; } @@ -851,7 +894,7 @@ class ImmutableCollections { // Callers are relying on this method to perform an implicit nullcheck // of pk. private int probe(Object pk) { - int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1; + int idx = Math.floorMod(pk.hashCode(), table.length >> 1) << 1; while (true) { @SuppressWarnings("unchecked") K ek = (K)table[idx]; From 3ff52c18c68e1ce0a365b134341fb4a4fc25665f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 24 Apr 2018 17:56:25 +0200 Subject: [PATCH 075/102] 8202200: set INCLUDE_SA to false on s390x by default Reviewed-by: ihse, erikj, jgeorge --- make/autoconf/jdk-options.m4 | 3 +++ src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 5fbf45ba8dd..21d77167dd3 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -238,6 +238,9 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], if test "x$OPENJDK_TARGET_OS" = xaix ; then INCLUDE_SA=false fi + if test "x$OPENJDK_TARGET_CPU" = xs390x ; then + INCLUDE_SA=false + fi AC_SUBST(INCLUDE_SA) # Compress jars diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h index da97116f3d7..1e965dd57dd 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h @@ -75,9 +75,6 @@ combination of ptrace and /proc calls. #include #define user_regs_struct pt_regs #endif -#if defined(s390x) -#include -#endif // This C bool type must be int for compatibility with Linux calls and // it would be a mistake to equivalence it to C++ bool on many platforms From af4695d7e47b5b4bd851aa19f4f8fc79e01abf8d Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 30 Apr 2018 11:48:03 +0200 Subject: [PATCH 076/102] 8202417: [TESTBUG] Broken hard-coded dependency in serviceability/sa/ClhsdbJhisto.java Reviewed-by: alanb --- test/hotspot/jtreg/serviceability/sa/ClhsdbJhisto.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbJhisto.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbJhisto.java index 76e32a62479..13728233986 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbJhisto.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbJhisto.java @@ -62,8 +62,7 @@ public class ClhsdbJhisto { "java.nio.HeapByteBuffer", "java.net.URI", "LingeredAppWithInterface", - "ParselTongue", - "ImmutableCollections$SetN$1")); + "ParselTongue")); test.run(theApp.getPid(), cmds, expStrMap, null); } catch (Exception ex) { From 8c235a30e72aa491d46bcc77d2091408ccd57352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Mon, 30 Apr 2018 12:19:53 +0200 Subject: [PATCH 077/102] 8202364: Add GCConfig::hs_err_name() to avoid GC-specific code in error reporting Reviewed-by: eosterlund, shade --- src/hotspot/share/gc/shared/gcConfig.cpp | 29 ++++++++++++++++++------ src/hotspot/share/gc/shared/gcConfig.hpp | 2 ++ src/hotspot/share/utilities/vmError.cpp | 12 ++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcConfig.cpp b/src/hotspot/share/gc/shared/gcConfig.cpp index f4f889bcc97..34a7d6de847 100644 --- a/src/hotspot/share/gc/shared/gcConfig.cpp +++ b/src/hotspot/share/gc/shared/gcConfig.cpp @@ -38,9 +38,10 @@ struct SupportedGC { bool& _flag; CollectedHeap::Name _name; GCArguments& _arguments; + const char* _hs_err_name; - SupportedGC(bool& flag, CollectedHeap::Name name, GCArguments& arguments) : - _flag(flag), _name(name), _arguments(arguments) {} + SupportedGC(bool& flag, CollectedHeap::Name name, GCArguments& arguments, const char* hs_err_name) : + _flag(flag), _name(name), _arguments(arguments), _hs_err_name(hs_err_name) {} }; static SerialArguments serialArguments; @@ -53,12 +54,12 @@ static G1Arguments g1Arguments; // Table of supported GCs, for translating between command // line flag, CollectedHeap::Name and GCArguments instance. static const SupportedGC SupportedGCs[] = { - SupportedGC(UseSerialGC, CollectedHeap::Serial, serialArguments), + SupportedGC(UseSerialGC, CollectedHeap::Serial, serialArguments, "serial gc"), #if INCLUDE_ALL_GCS - SupportedGC(UseParallelGC, CollectedHeap::Parallel, parallelArguments), - SupportedGC(UseParallelOldGC, CollectedHeap::Parallel, parallelArguments), - SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS, cmsArguments), - SupportedGC(UseG1GC, CollectedHeap::G1, g1Arguments), + SupportedGC(UseParallelGC, CollectedHeap::Parallel, parallelArguments, "parallel gc"), + SupportedGC(UseParallelOldGC, CollectedHeap::Parallel, parallelArguments, "parallel gc"), + SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS, cmsArguments, "concurrent mark sweep gc"), + SupportedGC(UseG1GC, CollectedHeap::G1, g1Arguments, "g1 gc"), #endif // INCLUDE_ALL_GCS }; @@ -172,6 +173,20 @@ bool GCConfig::is_gc_selected_ergonomically() { return _gc_selected_ergonomically; } +const char* GCConfig::hs_err_name() { + if (is_exactly_one_gc_selected()) { + // Exacly one GC selected + for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { + if (SupportedGCs[i]._flag) { + return SupportedGCs[i]._hs_err_name; + } + } + } + + // Zero or more than one GC selected + return "unknown gc"; +} + GCArguments* GCConfig::arguments() { assert(_arguments != NULL, "Not initialized"); return _arguments; diff --git a/src/hotspot/share/gc/shared/gcConfig.hpp b/src/hotspot/share/gc/shared/gcConfig.hpp index 989f6fa7518..97d5cd39eba 100644 --- a/src/hotspot/share/gc/shared/gcConfig.hpp +++ b/src/hotspot/share/gc/shared/gcConfig.hpp @@ -48,6 +48,8 @@ public: static bool is_gc_selected(CollectedHeap::Name name); static bool is_gc_selected_ergonomically(); + static const char* hs_err_name(); + static GCArguments* arguments(); }; diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index c936be78fc7..70aa67124e6 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -27,7 +27,7 @@ #include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" -#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/gcConfig.hpp" #include "logging/logConfiguration.hpp" #include "memory/resourceArea.hpp" #include "prims/whitebox.hpp" @@ -304,14 +304,6 @@ static void print_oom_reasons(outputStream* st) { st->print_cr("# This output file may be truncated or incomplete."); } -static const char* gc_mode() { - if (UseG1GC) return "g1 gc"; - if (UseParallelGC) return "parallel gc"; - if (UseConcMarkSweepGC) return "concurrent mark sweep gc"; - if (UseSerialGC) return "serial gc"; - return "ERROR in GC mode"; -} - static void report_vm_version(outputStream* st, char* buf, int buflen) { // VM version st->print_cr("#"); @@ -340,7 +332,7 @@ static void report_vm_version(outputStream* st, char* buf, int buflen) { "", "", #endif UseCompressedOops ? ", compressed oops" : "", - gc_mode(), + GCConfig::hs_err_name(), Abstract_VM_Version::vm_platform_string() ); } From b9490e57608049e6f90491ee41fcd87fa1f2776d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Mon, 30 Apr 2018 12:19:55 +0200 Subject: [PATCH 078/102] 8202366: Add macro for common loop in GCConfig Reviewed-by: eosterlund, shade --- src/hotspot/share/gc/shared/gcConfig.cpp | 35 +++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcConfig.cpp b/src/hotspot/share/gc/shared/gcConfig.cpp index 34a7d6de847..eab4932cd10 100644 --- a/src/hotspot/share/gc/shared/gcConfig.cpp +++ b/src/hotspot/share/gc/shared/gcConfig.cpp @@ -63,6 +63,9 @@ static const SupportedGC SupportedGCs[] = { #endif // INCLUDE_ALL_GCS }; +#define FOR_EACH_SUPPORTED_GC(var) \ + for (const SupportedGC* var = &SupportedGCs[0]; var < &SupportedGCs[ARRAY_SIZE(SupportedGCs)]; var++) + GCArguments* GCConfig::_arguments = NULL; bool GCConfig::_gc_selected_ergonomically = false; @@ -83,8 +86,8 @@ void GCConfig::select_gc_ergonomically() { } bool GCConfig::is_no_gc_selected() { - for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { - if (SupportedGCs[i]._flag) { + FOR_EACH_SUPPORTED_GC(gc) { + if (gc->_flag) { return false; } } @@ -95,11 +98,11 @@ bool GCConfig::is_no_gc_selected() { bool GCConfig::is_exactly_one_gc_selected() { CollectedHeap::Name selected = CollectedHeap::None; - for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { - if (SupportedGCs[i]._flag) { - if (SupportedGCs[i]._name == selected || selected == CollectedHeap::None) { + FOR_EACH_SUPPORTED_GC(gc) { + if (gc->_flag) { + if (gc->_name == selected || selected == CollectedHeap::None) { // Selected - selected = SupportedGCs[i]._name; + selected = gc->_name; } else { // More than one selected return false; @@ -127,9 +130,9 @@ GCArguments* GCConfig::select_gc() { if (is_exactly_one_gc_selected()) { // Exacly one GC selected - for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { - if (SupportedGCs[i]._flag) { - return &SupportedGCs[i]._arguments; + FOR_EACH_SUPPORTED_GC(gc) { + if (gc->_flag) { + return &gc->_arguments; } } } @@ -146,8 +149,8 @@ void GCConfig::initialize() { } bool GCConfig::is_gc_supported(CollectedHeap::Name name) { - for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { - if (SupportedGCs[i]._name == name) { + FOR_EACH_SUPPORTED_GC(gc) { + if (gc->_name == name) { // Supported return true; } @@ -158,8 +161,8 @@ bool GCConfig::is_gc_supported(CollectedHeap::Name name) { } bool GCConfig::is_gc_selected(CollectedHeap::Name name) { - for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { - if (SupportedGCs[i]._name == name && SupportedGCs[i]._flag) { + FOR_EACH_SUPPORTED_GC(gc) { + if (gc->_name == name && gc->_flag) { // Selected return true; } @@ -176,9 +179,9 @@ bool GCConfig::is_gc_selected_ergonomically() { const char* GCConfig::hs_err_name() { if (is_exactly_one_gc_selected()) { // Exacly one GC selected - for (size_t i = 0; i < ARRAY_SIZE(SupportedGCs); i++) { - if (SupportedGCs[i]._flag) { - return SupportedGCs[i]._hs_err_name; + FOR_EACH_SUPPORTED_GC(gc) { + if (gc->_flag) { + return gc->_hs_err_name; } } } From f7afa8ff53b7ce32629e360a703b11f6b512adb2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 30 Apr 2018 15:03:08 +0200 Subject: [PATCH 079/102] 8202105: Console echo is disabled when exiting jshell Preserving original terminal echo state when Console.readPassword finishes. Reviewed-by: sherman, martin --- .../share/classes/java/io/Console.java | 64 +++++++++---------- .../unix/native/libjava/Console_md.c | 11 ---- .../windows/native/libjava/Console_md.c | 11 ---- 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index e18837f2160..a2406ecd5db 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -311,9 +311,9 @@ public final class Console implements Flushable char[] passwd = null; synchronized (writeLock) { synchronized(readLock) { - boolean echoWasOn; + installShutdownHook(); try { - echoWasOn = echo(false); + restoreEcho = echo(false); } catch (IOException x) { throw new IOError(x); } @@ -326,7 +326,8 @@ public final class Console implements Flushable ioe = new IOError(x); } finally { try { - echo(echoWasOn); + if (restoreEcho) + restoreEcho = echo(true); } catch (IOException x) { if (ioe == null) ioe = new IOError(x); @@ -342,6 +343,31 @@ public final class Console implements Flushable return passwd; } + private void installShutdownHook() { + if (shutdownHookInstalled) + return; + try { + // Add a shutdown hook to restore console's echo state should + // it be necessary. + SharedSecrets.getJavaLangAccess() + .registerShutdownHook(0 /* shutdown hook invocation order */, + false /* only register if shutdown is not in progress */, + new Runnable() { + public void run() { + try { + if (restoreEcho) { + echo(true); + } + } catch (IOException x) { } + } + }); + } catch (IllegalStateException e) { + // shutdown is already in progress and readPassword is first used + // by a shutdown hook + } + shutdownHookInstalled = true; + } + /** * Reads a password or passphrase from the console with echoing disabled * @@ -372,6 +398,8 @@ public final class Console implements Flushable private Formatter formatter; private Charset cs; private char[] rcb; + private boolean restoreEcho; + private boolean shutdownHookInstalled; private static native String encoding(); /* * Sets the console echo status to {@code on} and returns the previous @@ -381,12 +409,6 @@ public final class Console implements Flushable * @return true if the previous console echo status is on */ private static native boolean echo(boolean on) throws IOException; - /* - * Returns the current console echo on/off status. - * @return true if the cosole echo is on - */ - private static native boolean echo0() throws IOException; - private static boolean echoOn; private char[] readline(boolean zeroOut) throws IOException { int len = reader.read(rcb, 0, rcb.length); @@ -531,25 +553,6 @@ public final class Console implements Flushable // Set up JavaIOAccess in SharedSecrets static { - try { - // Add a shutdown hook to restore console's echo state should - // it be necessary. - SharedSecrets.getJavaLangAccess() - .registerShutdownHook(0 /* shutdown hook invocation order */, - false /* only register if shutdown is not in progress */, - new Runnable() { - public void run() { - try { - if (cons != null) - echo(echoOn); - } catch (IOException x) { } - } - }); - } catch (IllegalStateException e) { - // shutdown is already in progress and console is first used - // by a shutdown hook - } - SharedSecrets.setJavaIOAccess(new JavaIOAccess() { public Console console() { if (istty()) { @@ -591,10 +594,5 @@ public final class Console implements Flushable readLock, cs)); rcb = new char[1024]; - try { - echoOn = echo0(); - } catch (IOException x) { - echoOn = true; - } } } diff --git a/src/java.base/unix/native/libjava/Console_md.c b/src/java.base/unix/native/libjava/Console_md.c index be0fcf1acb2..c8faa1656a6 100644 --- a/src/java.base/unix/native/libjava/Console_md.c +++ b/src/java.base/unix/native/libjava/Console_md.c @@ -67,14 +67,3 @@ Java_java_io_Console_echo(JNIEnv *env, } return old; } - -JNIEXPORT jboolean JNICALL -Java_java_io_Console_echo0(JNIEnv *env, jclass cls) { - struct termios tio; - int tty = fileno(stdin); - if (tcgetattr(tty, &tio) == -1) { - JNU_ThrowIOExceptionWithLastError(env, "tcgetattr failed"); - return JNI_TRUE; - } - return (tio.c_lflag & ECHO) != 0; -} diff --git a/src/java.base/windows/native/libjava/Console_md.c b/src/java.base/windows/native/libjava/Console_md.c index d3c74343b0b..173b2ffeb4a 100644 --- a/src/java.base/windows/native/libjava/Console_md.c +++ b/src/java.base/windows/native/libjava/Console_md.c @@ -82,14 +82,3 @@ Java_java_io_Console_echo(JNIEnv *env, jclass cls, jboolean on) } return old; } - -JNIEXPORT jboolean JNICALL -Java_java_io_Console_echo0(JNIEnv *env, jclass cls) -{ - DWORD fdwMode; - if (! GetConsoleMode(hStdIn, &fdwMode)) { - JNU_ThrowIOExceptionWithLastError(env, "GetConsoleMode failed"); - return JNI_TRUE; - } - return (fdwMode & ENABLE_ECHO_INPUT) != 0; -} From 0f478d2cfd45e32ffe4b40ca67ea9b5f1da64f80 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 30 Apr 2018 16:27:23 +0200 Subject: [PATCH 080/102] 8202419: Avoid creating Permission constants early Reviewed-by: alanb, mullan --- .../share/classes/java/lang/Thread.java | 7 ++----- .../java/lang/reflect/AccessibleObject.java | 16 +++++++--------- .../jdk/internal/reflect/ReflectionFactory.java | 7 +++---- .../sun/security/util/SecurityConstants.java | 17 ++++++++++++++--- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 9bdad3280de..0ff5ad8aac3 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -425,7 +425,8 @@ class Thread implements Runnable { */ if (security != null) { if (isCCLOverridden(getClass())) { - security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + security.checkPermission( + SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION); } } @@ -1703,10 +1704,6 @@ class Thread implements Runnable { return m; } - - private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION = - new RuntimePermission("enableContextClassLoaderOverride"); - /** cache of subclass security audit results */ /* Replace with ConcurrentReferenceHashMap when/if it appears in a future * release */ diff --git a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java index 9ea28b64d62..de0591d232b 100644 --- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java +++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java @@ -35,6 +35,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.ReflectionFactory; import sun.security.action.GetPropertyAction; +import sun.security.util.SecurityConstants; /** * The {@code AccessibleObject} class is the base class for {@code Field}, @@ -73,17 +74,14 @@ import sun.security.action.GetPropertyAction; */ public class AccessibleObject implements AnnotatedElement { - /** - * The Permission object that is used to check whether a client - * has sufficient privilege to defeat Java language access - * control checks. - */ - private static final java.security.Permission ACCESS_PERMISSION = - new ReflectPermission("suppressAccessChecks"); - static void checkPermission() { SecurityManager sm = System.getSecurityManager(); - if (sm != null) sm.checkPermission(ACCESS_PERMISSION); + if (sm != null) { + // SecurityConstants.ACCESS_PERMISSION is used to check + // whether a client has sufficient privilege to defeat Java + // language access control checks. + sm.checkPermission(SecurityConstants.ACCESS_PERMISSION); + } } /** diff --git a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index f919026b31d..f3c7741872b 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -47,6 +47,7 @@ import java.util.Properties; import jdk.internal.misc.VM; import sun.reflect.misc.ReflectUtil; import sun.security.action.GetPropertyAction; +import sun.security.util.SecurityConstants; /**

The master factory for all reflective objects, both those in java.lang.reflect (Fields, Methods, Constructors) as well as their @@ -63,8 +64,6 @@ import sun.security.action.GetPropertyAction; public class ReflectionFactory { private static boolean initted = false; - private static final Permission reflectionFactoryAccessPerm - = new RuntimePermission("reflectionFactoryAccess"); private static final ReflectionFactory soleInstance = new ReflectionFactory(); // Provides access to package-private mechanisms in java.lang.reflect private static volatile LangReflectAccess langReflectAccess; @@ -129,8 +128,8 @@ public class ReflectionFactory { public static ReflectionFactory getReflectionFactory() { SecurityManager security = System.getSecurityManager(); if (security != null) { - // TO DO: security.checkReflectionFactoryAccess(); - security.checkPermission(reflectionFactoryAccessPerm); + security.checkPermission( + SecurityConstants.REFLECTION_FACTORY_ACCESS_PERMISSION); } return soleInstance; } diff --git a/src/java.base/share/classes/sun/security/util/SecurityConstants.java b/src/java.base/share/classes/sun/security/util/SecurityConstants.java index c7099aca30f..ae935a66562 100644 --- a/src/java.base/share/classes/sun/security/util/SecurityConstants.java +++ b/src/java.base/share/classes/sun/security/util/SecurityConstants.java @@ -25,12 +25,10 @@ package sun.security.util; +import java.lang.reflect.ReflectPermission; import java.net.SocketPermission; import java.net.NetPermission; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.security.Permission; -import java.security.BasicPermission; import java.security.SecurityPermission; import java.security.AllPermission; import sun.security.action.GetPropertyAction; @@ -131,6 +129,10 @@ public final class SecurityConstants { public static final RuntimePermission GET_STACK_TRACE_PERMISSION = new RuntimePermission("getStackTrace"); + // java.lang.Thread + public static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION = + new RuntimePermission("enableContextClassLoaderOverride"); + // java.security.AccessControlContext public static final SecurityPermission CREATE_ACC_PERMISSION = new SecurityPermission("createAccessControlContext"); @@ -149,4 +151,13 @@ public final class SecurityConstants { public static final String PROVIDER_VER = GetPropertyAction.privilegedGetProperty("java.specification.version"); + + // java.lang.reflect.AccessibleObject + public static final ReflectPermission ACCESS_PERMISSION = + new ReflectPermission("suppressAccessChecks"); + + // sun.reflect.ReflectionFactory + public static final RuntimePermission REFLECTION_FACTORY_ACCESS_PERMISSION = + new RuntimePermission("reflectionFactoryAccess"); + } From 3e47229057288d31ba548bff5cb16829fa276d1d Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 30 Apr 2018 16:13:30 +0100 Subject: [PATCH 081/102] 8201545: InetAddress.getByName/getAllByName should clarify empty String behavior Reviewed-by: chegar --- .../share/classes/java/net/InetAddress.java | 28 +++++++++------- .../net/InetAddress/GetLoopbackAddress.java | 32 ++++++++++++++++--- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 044f326e6eb..74d559ebdd4 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1222,11 +1222,17 @@ class InetAddress implements java.io.Serializable { * supported. See here for a description of IPv6 * scoped addresses. * - *

If the host is {@code null} then an {@code InetAddress} - * representing an address of the loopback interface is returned. + *

If the host is {@code null} or {@code host.length()} is equal + * to zero, then an {@code InetAddress} representing an address of the + * loopback interface is returned. * See RFC 3330 * section 2 and RFC 2373 - * section 2.5.3.

+ * section 2.5.3. + * + *

If there is a security manager, and {@code host} is not {@code null} + * or {@code host.length() } is not equal to zero, the security manager's + * {@code checkConnect} method is called with the hostname and {@code -1} + * as its arguments to determine if the operation is allowed. * * @param host the specified host, or {@code null}. * @return an IP address for the given host name. @@ -1262,18 +1268,18 @@ class InetAddress implements java.io.Serializable { * also be qualified by appending a scoped zone identifier or scope_id. * The syntax and usage of scope_ids is described * here. - *

If the host is {@code null} then an {@code InetAddress} - * representing an address of the loopback interface is returned. + * + *

If the host is {@code null} or {@code host.length()} is equal + * to zero, then an {@code InetAddress} representing an address of the + * loopback interface is returned. * See RFC 3330 * section 2 and RFC 2373 * section 2.5.3.

* - *

If there is a security manager and {@code host} is not - * null and {@code host.length() } is not equal to zero, the - * security manager's - * {@code checkConnect} method is called - * with the hostname and {@code -1} - * as its arguments to see if the operation is allowed. + *

If there is a security manager, and {@code host} is not {@code null} + * or {@code host.length() } is not equal to zero, the security manager's + * {@code checkConnect} method is called with the hostname and {@code -1} + * as its arguments to determine if the operation is allowed. * * @param host the name of the host, or {@code null}. * @return an array of all the IP addresses for a given host name. diff --git a/test/jdk/java/net/InetAddress/GetLoopbackAddress.java b/test/jdk/java/net/InetAddress/GetLoopbackAddress.java index b55a2780d77..34e23124398 100644 --- a/test/jdk/java/net/InetAddress/GetLoopbackAddress.java +++ b/test/jdk/java/net/InetAddress/GetLoopbackAddress.java @@ -23,7 +23,7 @@ /** * @test - * @bug 6376404 + * @bug 6376404 8201545 * @summary InetAddress needs a getLoopbackAddress */ import java.net.*; @@ -45,17 +45,41 @@ public class GetLoopbackAddress } } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { InetAddress addr = InetAddress.getLoopbackAddress(); - if (!(addr.equals(IPv4Loopback) || addr.equals(IPv6Loopback))) + if (!(addr.equals(IPv4Loopback) || addr.equals(IPv6Loopback))) { throw new RuntimeException("Failed: getLoopbackAddress" + " not returning a valid loopback address"); + } InetAddress addr2 = InetAddress.getLoopbackAddress(); - if (addr != addr2) + if (addr != addr2) { throw new RuntimeException("Failed: getLoopbackAddress" + " should return a reference to the same InetAddress loopback instance."); + } + + InetAddress addrFromNullHost = InetAddress.getByName(null); + if (!addrFromNullHost.isLoopbackAddress()) { + throw new RuntimeException("getByName(null) did not return a" + + " loopback address, but " + addrFromNullHost); + } + InetAddress addrFromEmptyHost = InetAddress.getByName(""); + if (!addrFromEmptyHost.isLoopbackAddress()) { + throw new RuntimeException("getByName with a host of length == 0," + + " did not return a loopback address, but " + addrFromEmptyHost); + } + + InetAddress[] addrsByNull = InetAddress.getAllByName(null); + if (!addrsByNull[0].isLoopbackAddress()) { + throw new RuntimeException("getAllByName(null) did not return" + + " a loopback address, but " + addrsByNull[0]); + } + InetAddress[] addrsByEmpty = InetAddress.getAllByName(""); + if (!addrsByEmpty[0].isLoopbackAddress()) { + throw new RuntimeException("getAllByName with a host of length" + + " == 0, did not return a loopback address, but " + addrsByEmpty[0]); + } } } From b0268d4b00d768698fb511f78ed9b9eb5f1a79ce Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 30 Apr 2018 09:37:10 -0700 Subject: [PATCH 082/102] 8154204: [TESTBUG] Update DefaultUseWithClient test to handle client-less builds Removed the DefaultUseWithClient.java test Reviewed-by: hseigel, jiangli --- test/hotspot/jtreg/ProblemList.txt | 1 - test/hotspot/jtreg/TEST.groups | 1 - .../DefaultUseWithClient.java | 53 ------------------- 3 files changed, 55 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/SharedArchiveFile/DefaultUseWithClient.java diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d6427408fc0..31da4b62b4a 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -72,7 +72,6 @@ gc/stress/TestJNIBlockFullGC/TestJNIBlockFullGC.java 8192647 generic-all # :hotspot_runtime runtime/CompressedOops/UseCompressedOops.java 8079353 generic-all -runtime/SharedArchiveFile/DefaultUseWithClient.java 8154204 generic-all ############################################################################# diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 1ab2d17b912..ec65f733e01 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -235,7 +235,6 @@ tier1_runtime = \ -runtime/SelectionResolution/InvokeVirtualICCE.java \ -runtime/SelectionResolution/InvokeVirtualSuccessTest.java \ -runtime/SharedArchiveFile/CdsSameObjectAlignment.java \ - -runtime/SharedArchiveFile/DefaultUseWithClient.java \ -runtime/SharedArchiveFile/SharedBaseAddress.java \ -runtime/Thread/CancellableThreadTest.java \ -runtime/Thread/TestThreadDumpMonitorContention.java \ diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/DefaultUseWithClient.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/DefaultUseWithClient.java deleted file mode 100644 index 157789aa286..00000000000 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/DefaultUseWithClient.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 DefaultUseWithClient - * @summary Test default behavior of sharing with -client - * @requires vm.cds - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main DefaultUseWithClient - * @bug 8032224 - */ - -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Platform; -import java.io.File; - -public class DefaultUseWithClient { - public static void main(String[] args) throws Exception { - // On 32-bit windows CDS should be on by default in "-client" config - // Skip this test on any other platform - boolean is32BitWindows = (Platform.isWindows() && Platform.is32bit()); - if (!is32BitWindows) { - System.out.println("Test only applicable on 32-bit Windows. Skipping"); - return; - } - - CDSTestUtils.createArchiveAndCheck(); - CDSTestUtils.runWithArchiveAndCheck("-client", "-Xlog:cds"); - } -} From 9c2b1f2f7630e2f96834c5aced9e33a583af9681 Mon Sep 17 00:00:00 2001 From: Archana Nogriya Date: Mon, 30 Apr 2018 09:49:08 -0700 Subject: [PATCH 083/102] 8202383: Custom extensions for jvmti doc Reviewed-by: erikj --- make/Docs.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/Docs.gmk b/make/Docs.gmk index cd611e654cb..df5feca3208 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -561,7 +561,7 @@ $(eval $(call SetupCopyFiles, COPY_JDWP_PROTOCOL, \ JDK_SPECS_TARGETS += $(COPY_JDWP_PROTOCOL) # Get jvmti.html from the main jvm variant (all variants' jvmti.html are identical). -JVMTI_HTML := $(HOTSPOT_OUTPUTDIR)/variant-$(JVM_VARIANT_MAIN)/gensrc/jvmtifiles/jvmti.html +JVMTI_HTML ?= $(HOTSPOT_OUTPUTDIR)/variant-$(JVM_VARIANT_MAIN)/gensrc/jvmtifiles/jvmti.html $(eval $(call SetupCopyFiles, COPY_JVMTI_HTML, \ FILES := $(JVMTI_HTML), \ DEST := $(DOCS_OUTPUTDIR)/specs, \ From 8038a3507d3b546dbc1cc77b901e5882b7731a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Mon, 30 Apr 2018 21:17:37 +0200 Subject: [PATCH 084/102] 8202381: (Solaris) SIGBUS in # V [libjvm.so+0xcee494] jni_GetIntField+0x224 Reviewed-by: kbarrett, dcubed --- .../gc/shared/barrierSetAssembler_aarch64.cpp | 7 ++++--- .../gc/shared/barrierSetAssembler_aarch64.hpp | 3 ++- .../cpu/aarch64/jniFastGetField_aarch64.cpp | 2 +- .../sparc/gc/shared/barrierSetAssembler_sparc.cpp | 7 ++++--- .../sparc/gc/shared/barrierSetAssembler_sparc.hpp | 3 ++- src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp | 14 ++++++++------ .../cpu/x86/gc/shared/barrierSetAssembler_x86.cpp | 7 ++++--- .../cpu/x86/gc/shared/barrierSetAssembler_x86.hpp | 3 ++- src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp | 5 ++++- 9 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index ca3985ebe66..007f5250828 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -66,9 +66,10 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators } } -void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath) { +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath) { // If mask changes we need to ensure that the inverse is still encodable as an immediate STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); - __ andr(robj, robj, ~JNIHandles::weak_tag_mask); - __ ldr(robj, Address(robj, 0)); // *obj + __ andr(obj, obj, ~JNIHandles::weak_tag_mask); + __ ldr(obj, Address(obj, 0)); // *obj } diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index 6c6bed5d89a..15229d4bf84 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -40,7 +40,8 @@ public: virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2); - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath); + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath); virtual void barrier_stubs_init() {} }; diff --git a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp index d189a4697ae..f7fbe636313 100644 --- a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp @@ -85,7 +85,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { // robj is address dependent on rcounter. BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->try_resolve_jobject_in_native(masm, robj, rscratch1, slow); + bs->try_resolve_jobject_in_native(masm, c_rarg0, robj, rscratch1, slow); __ lsr(roffset, c_rarg2, 2); // offset diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp index 410da25f3cc..9c8afd26d2d 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp +++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp @@ -100,7 +100,8 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, } } -void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath) { - __ andn (robj, JNIHandles::weak_tag_mask, robj); - __ ld_ptr(robj, 0, robj); +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath) { + __ andn(obj, JNIHandles::weak_tag_mask, obj); + __ ld_ptr(obj, 0, obj); } diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp index 17546735cc8..0e91b042e66 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp @@ -45,7 +45,8 @@ public: Address src, Register dst, Register tmp); // Support for jniFastGetField to try resolving a jobject/jweak in native - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath); + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath); virtual void barrier_stubs_init() {} }; diff --git a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp b/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp index c1c4e2863b0..5520701365a 100644 --- a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp +++ b/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp @@ -70,18 +70,20 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ mov(O1, O5); + // Both O5 and G3 are clobbered by try_resolve_jobject_in_native. BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->try_resolve_jobject_in_native(masm, O1, G3_scratch, label1); + bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G3, label1); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); switch (type) { - case T_BOOLEAN: __ ldub (O1, O4, G3); break; - case T_BYTE: __ ldsb (O1, O4, G3); break; - case T_CHAR: __ lduh (O1, O4, G3); break; - case T_SHORT: __ ldsh (O1, O4, G3); break; - case T_INT: __ ld (O1, O4, G3); break; + case T_BOOLEAN: __ ldub (O5, O4, G3); break; + case T_BYTE: __ ldsb (O5, O4, G3); break; + case T_CHAR: __ lduh (O5, O4, G3); break; + case T_SHORT: __ ldsh (O5, O4, G3); break; + case T_INT: __ ld (O5, O4, G3); break; default: ShouldNotReachHere(); } diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 271caf9f374..93cb4e946e2 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -110,7 +110,8 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators } } -void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath) { - __ clear_jweak_tag(robj); - __ movptr(robj, Address(robj, 0)); +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath) { + __ clear_jweak_tag(obj); + __ movptr(obj, Address(obj, 0)); } diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index 35030b68a51..cac146f29b0 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -45,7 +45,8 @@ public: Address dst, Register val, Register tmp1, Register tmp2); // Support for jniFastGetField to try resolving a jobject/jweak in native - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register robj, Register tmp, Label& slowpath); + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath); virtual void barrier_stubs_init() {} }; diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp index b28ff9ff708..af3de9fc75c 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp @@ -44,6 +44,7 @@ // c_rarg1: obj // c_rarg2: jfield id +static const Register rtmp = r8; static const Register robj = r9; static const Register rcounter = r10; static const Register roffset = r11; @@ -86,8 +87,10 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset + // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->try_resolve_jobject_in_native(masm, robj, rscratch1, slow); + bs->try_resolve_jobject_in_native(masm, /* jni_env */ c_rarg0, robj, rtmp, slow); + DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); From cdd3f0ac395c4284fccc104678058e7427bd4457 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 30 Apr 2018 13:40:39 -0700 Subject: [PATCH 085/102] 8202284: FileChannel and FileOutpuStream variants of AtomicAppend should fail silently on macOS >= 10.13 Reviewed-by: chegar --- .../io/FileOutputStream/AtomicAppend.java | 19 +++++- .../channels/FileChannel/AtomicAppend.java | 16 ++++- test/lib/jdk/test/lib/Platform.java | 60 +++++++++++++++++-- 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/io/FileOutputStream/AtomicAppend.java b/test/jdk/java/io/FileOutputStream/AtomicAppend.java index ccc4b59cdb1..4afab60e7f9 100644 --- a/test/jdk/java/io/FileOutputStream/AtomicAppend.java +++ b/test/jdk/java/io/FileOutputStream/AtomicAppend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ * @test * @bug 6631352 * @summary Check that appends are atomic + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main AtomicAppend */ import java.io.File; @@ -33,6 +36,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; +import jdk.test.lib.Platform; + public class AtomicAppend { // Before the fix for // 6631352: Implement atomic append mode using FILE_APPEND_DATA (win) @@ -73,7 +78,17 @@ public class AtomicAppend { if (x == null ? y == null : x.equals(y)) pass(); else fail(x + " not equal to " + y);} public static void main(String[] args) throws Throwable { - new AtomicAppend().instanceMain(args);} + if (Platform.isOSX()) { + final String version = "10.13"; + int ineq = Platform.compareOsVersion(version); + if (ineq >= 0) { + System.out.format("Skipping test for macOS version %s >= %s%n", + Platform.getOsVersion(), version); + return; + } + } + new AtomicAppend().instanceMain(args); + } void instanceMain(String[] args) throws Throwable { try {test(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); diff --git a/test/jdk/java/nio/channels/FileChannel/AtomicAppend.java b/test/jdk/java/nio/channels/FileChannel/AtomicAppend.java index 8e00c60bfd4..4d8562a4e23 100644 --- a/test/jdk/java/nio/channels/FileChannel/AtomicAppend.java +++ b/test/jdk/java/nio/channels/FileChannel/AtomicAppend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,9 @@ /* * @test * @summary Check that appends are atomic + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main AtomicAppend * @key randomness */ @@ -40,6 +43,8 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import static java.nio.file.StandardOpenOption.*; +import jdk.test.lib.Platform; + public class AtomicAppend { static final Random rand = new Random(); @@ -76,6 +81,15 @@ public class AtomicAppend { } public static void main(String[] args) throws Throwable { + if (Platform.isOSX()) { + final String version = "10.13"; + int ineq = Platform.compareOsVersion(version); + if (ineq >= 0) { + System.out.format("Skipping test for macOS version %s >= %s%n", + Platform.getOsVersion(), version); + return; + } + } final int nThreads = 16; final int writes = 1000; final File file = File.createTempFile("foo", null); diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index d38a137068e..130d3da140b 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,17 @@ package jdk.test.lib; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class Platform { public static final String vmName = System.getProperty("java.vm.name"); public static final String vmInfo = System.getProperty("java.vm.info"); private static final String osVersion = System.getProperty("os.version"); + private static String[] osVersionTokens; private static int osVersionMajor = -1; private static int osVersionMinor = -1; private static final String osName = System.getProperty("os.name"); @@ -124,12 +129,12 @@ public class Platform { // Os version support. private static void init_version() { + osVersionTokens = osVersion.split("\\."); try { - final String[] tokens = osVersion.split("\\."); - if (tokens.length > 0) { - osVersionMajor = Integer.parseInt(tokens[0]); - if (tokens.length > 1) { - osVersionMinor = Integer.parseInt(tokens[1]); + if (osVersionTokens.length > 0) { + osVersionMajor = Integer.parseInt(osVersionTokens[0]); + if (osVersionTokens.length > 1) { + osVersionMinor = Integer.parseInt(osVersionTokens[1]); } } } catch (NumberFormatException e) { @@ -137,6 +142,10 @@ public class Platform { } } + public static String getOsVersion() { + return osVersion; + } + // Returns major version number from os.version system property. // E.g. 5 on Solaris 10 and 3 on SLES 11.3 (for the linux kernel version). public static int getOsVersionMajor() { @@ -151,6 +160,45 @@ public class Platform { return osVersionMinor; } + /** + * Compares the platform version with the supplied version. The + * version must be of the form a[.b[.c[.d...]]] where a, b, c, d, ... + * are decimal integers. + * + * @throws NullPointerException if the parameter is null + * @throws NumberFormatException if there is an error parsing either + * version as split into component strings + * @return -1, 0, or 1 according to whether the platform version is + * less than, equal to, or greater than the supplied version + */ + public static int compareOsVersion(String version) { + if (osVersionTokens == null) init_version(); + + Objects.requireNonNull(version); + + List s1 = Arrays + .stream(osVersionTokens) + .map(Integer::valueOf) + .collect(Collectors.toList()); + List s2 = Arrays + .stream(version.split("\\.")) + .map(Integer::valueOf) + .collect(Collectors.toList()); + + int count = Math.max(s1.size(), s2.size()); + for (int i = 0; i < count; i++) { + int i1 = i < s1.size() ? s1.get(i) : 0; + int i2 = i < s2.size() ? s2.get(i) : 0; + if (i1 > i2) { + return 1; + } else if (i2 > i1) { + return -1; + } + } + + return 0; + } + public static boolean isDebugBuild() { return (jdkDebug.toLowerCase().contains("debug")); } From 20edc74068a79586eda5943cbd3e47f9377f8478 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Mon, 30 Apr 2018 16:59:05 -0400 Subject: [PATCH 086/102] 8193213: Make the UseAppCDS option obsolete 8182731: Odd handling of -XX:-UseAppCDS and -XX:SharedArchiveFile Application class data sharing is enabled without -XX:+UseAppCDS. SharedArchiveFile is now a product flag. Reviewed-by: dholmes, ihse, erikj, ccheung --- make/GenerateLinkOptData.gmk | 5 +- .../share/classfile/classListParser.cpp | 5 +- src/hotspot/share/classfile/classLoader.cpp | 39 -------- src/hotspot/share/classfile/classLoader.hpp | 1 - .../share/classfile/classLoaderExt.cpp | 37 ++++---- .../share/classfile/classLoaderExt.hpp | 11 +-- .../share/classfile/sharedClassUtil.cpp | 27 +++--- .../share/classfile/sharedClassUtil.hpp | 4 + .../share/classfile/sharedPathsMiscInfo.cpp | 2 +- .../share/classfile/systemDictionary.cpp | 10 +- .../classfile/systemDictionaryShared.cpp | 95 ++++++++++--------- src/hotspot/share/memory/filemap.cpp | 51 +++++++--- src/hotspot/share/memory/filemap.hpp | 3 +- src/hotspot/share/memory/metaspaceShared.cpp | 7 +- src/hotspot/share/runtime/arguments.cpp | 9 +- src/hotspot/share/runtime/globals.hpp | 6 +- .../compiler/aot/fingerprint/CDSDumper.java | 3 - .../aot/fingerprint/SelfChangedCDS.java | 12 +-- .../SharedArchiveFile/BootAppendTests.java | 5 +- .../DumpSharedDictionary.java | 2 - .../NonBootLoaderClasses.java | 11 ++- .../SharedArchiveFile/SASymbolTableTest.java | 1 - .../SharedArchiveFile/SharedArchiveFile.java | 2 - .../runtime/appcds/DirClasspathTest.java | 39 +++++--- .../jtreg/runtime/appcds/DumpClassList.java | 3 +- .../appcds/GraalWithLimitedMetaspace.java | 2 - .../runtime/appcds/MismatchedUseAppCDS.java | 6 +- .../runtime/appcds/SpecifySysLoaderProp.java | 8 +- .../jtreg/runtime/appcds/TestCommon.java | 14 +-- .../jtreg/runtime/appcds/VerifierTest.java | 1 - .../sharedStrings/SharedStringsBasic.java | 2 - .../appcds/sharedStrings/SysDictCrash.java | 2 - test/lib/jdk/test/lib/cds/CDSTestUtils.java | 2 - 33 files changed, 189 insertions(+), 238 deletions(-) diff --git a/make/GenerateLinkOptData.gmk b/make/GenerateLinkOptData.gmk index 0f5523f6ec3..7358589e6f3 100644 --- a/make/GenerateLinkOptData.gmk +++ b/make/GenerateLinkOptData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,11 +61,12 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR) $(call MakeDir, $(LINK_OPT_DIR)) $(call LogInfo, Generating $(patsubst $(OUTPUTDIR)/%, %, $@)) $(call LogInfo, Generating $(patsubst $(OUTPUTDIR)/%, %, $(JLI_TRACE_FILE))) - $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \ + $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \ -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \ -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ build.tools.classlist.HelloClasslist \ $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE) + $(GREP) -v HelloClasslist $@.raw > $@ # The jli trace is created by the same recipe as classlist. By declaring these # dependencies, make will correctly rebuild both jli trace and classlist diff --git a/src/hotspot/share/classfile/classListParser.cpp b/src/hotspot/share/classfile/classListParser.cpp index 39b604796e9..43107ee426e 100644 --- a/src/hotspot/share/classfile/classListParser.cpp +++ b/src/hotspot/share/classfile/classListParser.cpp @@ -283,7 +283,6 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS error("AppCDS custom class loaders not supported on this platform"); #endif - assert(UseAppCDS, "must be"); if (!is_super_specified()) { error("If source location is specified, super class must be also specified"); } @@ -383,9 +382,7 @@ Klass* ClassListParser::load_current_class(TRAPS) { } else { // If "source:" tag is specified, all super class and super interfaces must be specified in the // class list file. - if (UseAppCDS) { - klass = load_class_from_source(class_name_symbol, CHECK_NULL); - } + klass = load_class_from_source(class_name_symbol, CHECK_NULL); } if (klass != NULL && klass->is_instance_klass() && is_id_specified()) { diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 05da77b79a2..60177720fe2 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -270,14 +270,6 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { // check if file exists struct stat st; if (os::stat(path, &st) == 0) { -#if INCLUDE_CDS - if (DumpSharedSpaces) { - // We have already check in ClassLoader::check_shared_classpath() that the directory is empty, so - // we should never find a file underneath it -- unless user has added a new file while we are running - // the dump, in which case let's quit! - ShouldNotReachHere(); - } -#endif // found file, open it int file_handle = os::open(path, 0, 0); if (file_handle != -1) { @@ -644,24 +636,6 @@ void ClassLoader::trace_class_path(const char* msg, const char* name) { } } -#if INCLUDE_CDS -void ClassLoader::check_shared_classpath(const char *path) { - if (strcmp(path, "") == 0) { - exit_with_path_failure("Cannot have empty path in archived classpaths", NULL); - } - - struct stat st; - if (os::stat(path, &st) == 0) { - if ((st.st_mode & S_IFMT) != S_IFREG) { // is not a regular file - if (!os::dir_is_empty(path)) { - tty->print_cr("Error: non-empty directory '%s'", path); - exit_with_path_failure("CDS allows only empty directories in archived classpaths", NULL); - } - } - } -} -#endif - void ClassLoader::setup_bootstrap_search_path() { const char* sys_class_path = Arguments::get_sysclasspath(); if (PrintSharedArchiveAndExit) { @@ -713,8 +687,6 @@ void ClassLoader::setup_app_search_path(const char *class_path) { strncpy(path, &class_path[start], end - start); path[end - start] = '\0'; - check_shared_classpath(path); - update_class_path_entry_list(path, false, false); while (class_path[end] == os::path_separator()[0]) { @@ -757,7 +729,6 @@ void ClassLoader::update_module_path_entry_list(const char *path, TRAPS) { } void ClassLoader::setup_module_search_path(const char* path, TRAPS) { - check_shared_classpath(path); update_module_path_entry_list(path, THREAD); } #endif // INCLUDE_CDS @@ -886,11 +857,6 @@ void ClassLoader::setup_boot_search_path(const char *class_path) { update_class_path_entry_list(path, false, true); } -#if INCLUDE_CDS - if (DumpSharedSpaces) { - check_shared_classpath(path); - } -#endif while (class_path[end] == os::path_separator()[0]) { end++; } @@ -1082,11 +1048,6 @@ void ClassLoader::add_to_app_classpath_entries(const char* path, if (entry->is_jar_file()) { ClassLoaderExt::process_jar_manifest(entry, check_for_duplicates); - } else { - if (!os::dir_is_empty(path)) { - tty->print_cr("Error: non-empty directory '%s'", path); - exit_with_path_failure("Cannot have non-empty directory in app classpaths", NULL); - } } #endif } diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index c2038158c40..ac6ca416f96 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -422,7 +422,6 @@ class ClassLoader: AllStatic { } return num_entries; } - static void check_shared_classpath(const char *path); static void finalize_shared_paths_misc_info(); static int get_shared_paths_misc_info_size(); static void* get_shared_paths_misc_info(); diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index 44b55c3b740..b182e6e5d86 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -54,8 +54,17 @@ jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_class bool ClassLoaderExt::_has_app_classes = false; bool ClassLoaderExt::_has_platform_classes = false; +void ClassLoaderExt::append_boot_classpath(ClassPathEntry* new_entry) { +#if INCLUDE_CDS + warning("Sharing is only supported for boot loader classes because bootstrap classpath has been appended"); + FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); + header->set_has_platform_or_app_classes(false); +#endif + ClassLoader::add_to_boot_append_entries(new_entry); +} + void ClassLoaderExt::setup_app_search_path() { - assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS"); + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); _app_class_paths_start_index = ClassLoader::num_boot_classpath_entries(); char* app_class_path = os::strdup(Arguments::get_appclasspath()); @@ -85,8 +94,8 @@ void ClassLoaderExt::process_module_table(ModuleEntryTable* met, TRAPS) { } } } -void ClassLoaderExt::setup_module_search_path(TRAPS) { - assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS"); +void ClassLoaderExt::setup_module_paths(TRAPS) { + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); _app_module_paths_start_index = ClassLoader::num_boot_classpath_entries() + ClassLoader::num_app_classpath_entries(); Handle system_class_loader (THREAD, SystemDictionary::java_system_loader()); @@ -215,16 +224,8 @@ void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry, } void ClassLoaderExt::setup_search_paths() { - if (UseAppCDS) { - shared_paths_misc_info()->record_app_offset(); - ClassLoaderExt::setup_app_search_path(); - } -} - -void ClassLoaderExt::setup_module_paths(TRAPS) { - if (UseAppCDS) { - ClassLoaderExt::setup_module_search_path(THREAD); - } + shared_paths_misc_info()->record_app_offset(); + ClassLoaderExt::setup_app_search_path(); } Thread* ClassLoaderExt::Context::_dump_thread = NULL; @@ -251,10 +252,8 @@ void ClassLoaderExt::record_result(ClassLoaderExt::Context *context, } void ClassLoaderExt::finalize_shared_paths_misc_info() { - if (UseAppCDS) { - if (!_has_app_classes) { - shared_paths_misc_info()->pop_app(); - } + if (!_has_app_classes) { + shared_paths_misc_info()->pop_app(); } } @@ -264,7 +263,7 @@ void ClassLoaderExt::finalize_shared_paths_misc_info() { InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS) { assert(name != NULL, "invariant"); - assert(DumpSharedSpaces && UseAppCDS, "this function is only used with -Xshare:dump and -XX:+UseAppCDS"); + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); ResourceMark rm(THREAD); const char* class_name = name->as_C_string(); @@ -322,7 +321,7 @@ static GrowableArray* cached_path_entries = NULL; ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(const char* path, TRAPS) { // This is called from dump time so it's single threaded and there's no need for a lock. - assert(DumpSharedSpaces && UseAppCDS, "this function is only used with -Xshare:dump and -XX:+UseAppCDS"); + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); if (cached_path_entries == NULL) { cached_path_entries = new (ResourceObj::C_HEAP, mtClass) GrowableArray(20, /*c heap*/ true); } diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index a4b3cc6cb79..a452acc4ed0 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -95,7 +95,6 @@ private: static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size); static void setup_app_search_path(); // Only when -Xshare:dump static void process_module_table(ModuleEntryTable* met, TRAPS); - static void setup_module_search_path(TRAPS); static SharedPathsMiscInfoExt* shared_paths_misc_info() { return (SharedPathsMiscInfoExt*)_shared_paths_misc_info; } @@ -112,15 +111,7 @@ public: CDS_ONLY(static void process_jar_manifest(ClassPathEntry* entry, bool check_for_duplicates);) // Called by JVMTI code to add boot classpath - static void append_boot_classpath(ClassPathEntry* new_entry) { -#if INCLUDE_CDS - if (UseAppCDS) { - warning("UseAppCDS is disabled because bootstrap classpath has been appended"); - UseAppCDS = false; - } -#endif - ClassLoader::add_to_boot_append_entries(new_entry); - } + static void append_boot_classpath(ClassPathEntry* new_entry); static void setup_search_paths() NOT_CDS_RETURN; static void setup_module_paths(TRAPS) NOT_CDS_RETURN; diff --git a/src/hotspot/share/classfile/sharedClassUtil.cpp b/src/hotspot/share/classfile/sharedClassUtil.cpp index 2d78e026c94..0e215cbb353 100644 --- a/src/hotspot/share/classfile/sharedClassUtil.cpp +++ b/src/hotspot/share/classfile/sharedClassUtil.cpp @@ -173,11 +173,9 @@ void SharedClassUtil::initialize(TRAPS) { int size = FileMapInfo::get_number_of_shared_paths(); if (size > 0) { SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD); - if (!DumpSharedSpaces) { - FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); - ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index); - ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index); - } + FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); + ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index); + ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index); } } @@ -229,19 +227,20 @@ void FileMapHeaderExt::populate(FileMapInfo* mapinfo, size_t alignment) { } bool FileMapHeaderExt::validate() { - if (UseAppCDS) { - const char* prop = Arguments::get_property("java.system.class.loader"); - if (prop != NULL) { - warning("UseAppCDS is disabled because the java.system.class.loader property is specified (value = \"%s\"). " - "To enable UseAppCDS, this property must be not be set", prop); - UseAppCDS = false; - } - } - if (!FileMapInfo::FileMapHeader::validate()) { return false; } + // This must be done after header validation because it might change the + // header data + const char* prop = Arguments::get_property("java.system.class.loader"); + if (prop != NULL) { + warning("Archived non-system classes are disabled because the " + "java.system.class.loader property is specified (value = \"%s\"). " + "To use archived non-system classes, this property must be not be set", prop); + _has_platform_or_app_classes = false; + } + // For backwards compatibility, we don't check the verification setting // if the archive only contains system classes. if (_has_platform_or_app_classes && diff --git a/src/hotspot/share/classfile/sharedClassUtil.hpp b/src/hotspot/share/classfile/sharedClassUtil.hpp index 0d9a581a2e3..caccfce9deb 100644 --- a/src/hotspot/share/classfile/sharedClassUtil.hpp +++ b/src/hotspot/share/classfile/sharedClassUtil.hpp @@ -43,6 +43,10 @@ public: FileMapHeaderExt() { _has_platform_or_app_classes = true; } + void set_has_platform_or_app_classes(bool v) { + _has_platform_or_app_classes = v; + } + bool has_platform_or_app_classes() { return _has_platform_or_app_classes; } virtual void populate(FileMapInfo* mapinfo, size_t alignment); virtual bool validate(); }; diff --git a/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp b/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp index 3386052a509..5cb57e40559 100644 --- a/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp +++ b/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp @@ -141,7 +141,7 @@ bool SharedPathsMiscInfo::check(jint type, const char* path) { switch (type) { case BOOT: // In the future we should perform the check based on the content of the mapped archive. - if (UseAppCDS && os::file_name_strcmp(path, Arguments::get_sysclasspath()) != 0) { + if (os::file_name_strcmp(path, Arguments::get_sysclasspath()) != 0) { return fail("[BOOT classpath mismatch, actual =", Arguments::get_sysclasspath()); } break; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 7c346b1a105..8035981b52c 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -3059,13 +3059,9 @@ class CombineDictionariesClosure : public CLDClosure { // During run time, we only have one shared dictionary. void SystemDictionary::combine_shared_dictionaries() { assert(DumpSharedSpaces, "dump time only"); - // If AppCDS isn't enabled, we only dump the classes in the boot loader dictionary - // into the shared archive. - if (UseAppCDS) { - Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary(); - CombineDictionariesClosure cdc(master_dictionary); - ClassLoaderDataGraph::cld_do(&cdc); - } + Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary(); + CombineDictionariesClosure cdc(master_dictionary); + ClassLoaderDataGraph::cld_do(&cdc); // These tables are no longer valid or necessary. Keeping them around will // cause SystemDictionary::verify() to fail. Let's empty them. diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index d9a6fb8555f..84cb861e1ce 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -360,9 +360,8 @@ Handle SystemDictionaryShared::init_security_info(Handle class_loader, InstanceK bool SystemDictionaryShared::is_sharing_possible(ClassLoaderData* loader_data) { oop class_loader = loader_data->class_loader(); return (class_loader == NULL || - (UseAppCDS && (SystemDictionary::is_system_class_loader(class_loader) || - SystemDictionary::is_platform_class_loader(class_loader))) - ); + SystemDictionary::is_system_class_loader(class_loader) || + SystemDictionary::is_platform_class_loader(class_loader)); } // Currently AppCDS only archives classes from the run-time image, the @@ -508,57 +507,59 @@ bool SystemDictionaryShared::is_shared_class_visible_for_classloader( // InstanceKlass* SystemDictionaryShared::find_or_load_shared_class( Symbol* name, Handle class_loader, TRAPS) { - if (DumpSharedSpaces) { - return NULL; - } - InstanceKlass* k = NULL; - if (shared_dictionary() != NULL && - UseAppCDS && (SystemDictionary::is_system_class_loader(class_loader()) || - SystemDictionary::is_platform_class_loader(class_loader()))) { - - // Fix for 4474172; see evaluation for more details - class_loader = Handle( - THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); - ClassLoaderData *loader_data = register_loader(class_loader); - Dictionary* dictionary = loader_data->dictionary(); - - unsigned int d_hash = dictionary->compute_hash(name); - - bool DoObjectLock = true; - if (is_parallelCapable(class_loader)) { - DoObjectLock = false; + if (UseSharedSpaces) { + FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); + if (!header->has_platform_or_app_classes()) { + return NULL; } - // Make sure we are synchronized on the class loader before we proceed - // - // Note: currently, find_or_load_shared_class is called only from - // JVM_FindLoadedClass and used for PlatformClassLoader and AppClassLoader, - // which are parallel-capable loaders, so this lock is NOT taken. - Handle lockObject = compute_loader_lock_object(class_loader, THREAD); - check_loader_lock_contention(lockObject, THREAD); - ObjectLocker ol(lockObject, THREAD, DoObjectLock); + if (shared_dictionary() != NULL && + (SystemDictionary::is_system_class_loader(class_loader()) || + SystemDictionary::is_platform_class_loader(class_loader()))) { + // Fix for 4474172; see evaluation for more details + class_loader = Handle( + THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); + ClassLoaderData *loader_data = register_loader(class_loader); + Dictionary* dictionary = loader_data->dictionary(); - { - MutexLocker mu(SystemDictionary_lock, THREAD); - Klass* check = find_class(d_hash, name, dictionary); - if (check != NULL) { - return InstanceKlass::cast(check); + unsigned int d_hash = dictionary->compute_hash(name); + + bool DoObjectLock = true; + if (is_parallelCapable(class_loader)) { + DoObjectLock = false; + } + + // Make sure we are synchronized on the class loader before we proceed + // + // Note: currently, find_or_load_shared_class is called only from + // JVM_FindLoadedClass and used for PlatformClassLoader and AppClassLoader, + // which are parallel-capable loaders, so this lock is NOT taken. + Handle lockObject = compute_loader_lock_object(class_loader, THREAD); + check_loader_lock_contention(lockObject, THREAD); + ObjectLocker ol(lockObject, THREAD, DoObjectLock); + + { + MutexLocker mu(SystemDictionary_lock, THREAD); + Klass* check = find_class(d_hash, name, dictionary); + if (check != NULL) { + return InstanceKlass::cast(check); + } + } + + k = load_shared_class_for_builtin_loader(name, class_loader, THREAD); + if (k != NULL) { + define_instance_class(k, CHECK_NULL); } } - - k = load_shared_class_for_builtin_loader(name, class_loader, THREAD); - if (k != NULL) { - define_instance_class(k, CHECK_NULL); - } } - return k; } InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader( Symbol* class_name, Handle class_loader, TRAPS) { - assert(UseAppCDS && shared_dictionary() != NULL, "already checked"); + assert(UseSharedSpaces, "must be"); + assert(shared_dictionary() != NULL, "already checked"); Klass* k = shared_dictionary()->find_class_for_builtin_loader(class_name); if (k != NULL) { @@ -609,13 +610,13 @@ void SystemDictionaryShared::allocate_shared_data_arrays(int size, TRAPS) { allocate_shared_jar_manifest_array(size, CHECK); } - +// This function is called for loading only UNREGISTERED classes InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_name, Handle class_loader, Handle protection_domain, const ClassFileStream* cfs, TRAPS) { - if (!UseAppCDS || shared_dictionary() == NULL) { + if (shared_dictionary() == NULL) { return NULL; } if (class_name == NULL) { // don't do this for anonymous classes @@ -624,7 +625,6 @@ InstanceKlass* SystemDictionaryShared::lookup_from_stream(const Symbol* class_na if (class_loader.is_null() || SystemDictionary::is_system_class_loader(class_loader()) || SystemDictionary::is_platform_class_loader(class_loader())) { - // This function is called for loading only UNREGISTERED classes. // Do nothing for the BUILTIN loaders. return NULL; } @@ -686,11 +686,12 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( return shared_klass; } -bool SystemDictionaryShared::add_non_builtin_klass(Symbol* name, ClassLoaderData* loader_data, +bool SystemDictionaryShared::add_non_builtin_klass(Symbol* name, + ClassLoaderData* loader_data, InstanceKlass* k, TRAPS) { assert(DumpSharedSpaces, "only when dumping"); - assert(UseAppCDS && boot_loader_dictionary() != NULL, "must be"); + assert(boot_loader_dictionary() != NULL, "must be"); if (boot_loader_dictionary()->add_non_builtin_klass(name, loader_data, k)) { MutexLocker mu_r(Compile_lock, THREAD); // not really necessary, but add_to_hierarchy asserts this. diff --git a/src/hotspot/share/memory/filemap.cpp b/src/hotspot/share/memory/filemap.cpp index be7fd8d61ed..165ea6f5840 100644 --- a/src/hotspot/share/memory/filemap.cpp +++ b/src/hotspot/share/memory/filemap.cpp @@ -207,10 +207,6 @@ void SharedClassPathEntry::init(const char* name, TRAPS) { struct stat st; if (os::stat(name, &st) == 0) { if ((st.st_mode & S_IFMT) == S_IFDIR) { - if (!os::dir_is_empty(name)) { - ClassLoader::exit_with_path_failure( - "Cannot have non-empty directory in archived classpaths", name); - } _is_dir = true; } else { _is_dir = false; @@ -232,6 +228,8 @@ void SharedClassPathEntry::init(const char* name, TRAPS) { } bool SharedClassPathEntry::validate(bool is_class_path) { + assert(UseSharedSpaces, "runtime only"); + struct stat st; const char* name = this->name(); bool ok = true; @@ -335,22 +333,49 @@ void FileMapInfo::allocate_shared_path_table() { assert(i == num_entries, "number of shared path entry mismatch"); } -// This function should only be called during run time with UseSharedSpaces enabled. -bool FileMapInfo::validate_shared_path_table() { - _validating_shared_path_table = true; +void FileMapInfo::check_nonempty_dir_in_shared_path_table() { + assert(DumpSharedSpaces, "dump time only"); + bool has_nonempty_dir = false; + + int end = _shared_path_table_size; + if (!ClassLoaderExt::has_platform_or_app_classes()) { + // only check the boot path if no app class is loaded + end = ClassLoaderExt::app_class_paths_start_index(); + } + + for (int i = 0; i < end; i++) { + SharedClassPathEntry *e = shared_path(i); + if (e->is_dir()) { + const char* path = e->name(); + if (!os::dir_is_empty(path)) { + tty->print_cr("Error: non-empty directory '%s'", path); + has_nonempty_dir = true; + } + } + } + + if (has_nonempty_dir) { + ClassLoader::exit_with_path_failure("Cannot have non-empty directory in paths", NULL); + } +} + +bool FileMapInfo::validate_shared_path_table() { + assert(UseSharedSpaces, "runtime only"); + + _validating_shared_path_table = true; _shared_path_table = _header->_shared_path_table; _shared_path_entry_size = _header->_shared_path_entry_size; _shared_path_table_size = _header->_shared_path_table_size; - // Note: _app_module_paths_start_index may not have a valid value if the UseAppCDS flag - // wasn't enabled during dump time. Therefore, we need to use the smaller of - // _shared_path_table_size and _app_module_paths_start_index for the _app_module_paths_start_index. FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); - int module_paths_start_index = (header->_app_module_paths_start_index >= _shared_path_table_size) ? - _shared_path_table_size : header->_app_module_paths_start_index; + int module_paths_start_index = header->_app_module_paths_start_index; - int count = _shared_path_table_size; + // If the shared archive contain app or platform classes, validate all entries + // in the shared path table. Otherwise, only validate the boot path entries (with + // entry index < _app_class_paths_start_index). + int count = header->has_platform_or_app_classes() ? + _shared_path_table_size : header->_app_class_paths_start_index; for (int i=0; iclass_loader_data()->is_the_null_class_loader_data()) { - // AppCDS is not enabled. Let's omit non-boot classes. - return; - } - if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) { if (k->is_instance_klass() && InstanceKlass::cast(k)->signers() != NULL) { // Mark any class with signers and don't add to the _global_klass_objects @@ -1327,6 +1322,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { void VM_PopulateDumpSharedSpace::doit() { Thread* THREAD = VMThread::vm_thread(); + FileMapInfo::check_nonempty_dir_in_shared_path_table(); + NOT_PRODUCT(SystemDictionary::verify();) // The following guarantee is meant to ensure that no loader constraints // exist yet, since the constraints table is not shared. This becomes diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 1e49fe1d35d..04a55da18c8 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -545,6 +545,7 @@ static SpecialFlag const special_jvm_flags[] = { { "SharedMiscDataSize", JDK_Version::undefined(), JDK_Version::jdk(10), JDK_Version::undefined() }, { "SharedMiscCodeSize", JDK_Version::undefined(), JDK_Version::jdk(10), JDK_Version::undefined() }, { "UseUTCFileTimestamp", JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) }, + { "UseAppCDS", JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS { "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, @@ -3889,14 +3890,6 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, vm_exit(0); } #endif - - if (match_option(option, "-XX:+UseAppCDS")) { - JVMFlag* flag = JVMFlag::find_flag("SharedArchiveFile", 17, true, true); - if (flag->is_diagnostic()) { - flag->clear_diagnostic(); - } - continue; - } } return JNI_OK; } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 1e03437ea4c..52ffd446e41 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -2480,10 +2480,6 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); "Address to allocate shared memory region for class data") \ range(0, SIZE_MAX) \ \ - product(bool, UseAppCDS, false, \ - "Enable Application Class Data Sharing when using shared spaces") \ - writeable(CommandLineOnly) \ - \ product(ccstr, SharedArchiveConfigFile, NULL, \ "Data to add to the CDS archive file") \ \ @@ -2589,7 +2585,7 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); product(ccstr, SharedClassListFile, NULL, \ "Override the default CDS class list") \ \ - diagnostic(ccstr, SharedArchiveFile, NULL, \ + product(ccstr, SharedArchiveFile, NULL, \ "Override the default location of the CDS archive file") \ \ product(ccstr, ExtraSharedClassListFile, NULL, \ diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java index b0bc027ced5..7ef39249a6a 100644 --- a/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java +++ b/test/hotspot/jtreg/compiler/aot/fingerprint/CDSDumper.java @@ -53,9 +53,6 @@ public class CDSDumper { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( heapsize, "-XX:+IgnoreUnrecognizedVMOptions", - "-XX:+UnlockCommercialFeatures", - "-XX:+UseAppCDS", - "-XX:+UnlockDiagnosticVMOptions", "-cp", classpath, "-XX:ExtraSharedClassListFile=" + classlist, "-XX:SharedArchiveFile=" + archive, diff --git a/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java b/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java index e63dc2ea97e..52cf5806c02 100644 --- a/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java +++ b/test/hotspot/jtreg/compiler/aot/fingerprint/SelfChangedCDS.java @@ -43,9 +43,9 @@ * compiler.aot.fingerprint.Blah TEST-UNMODIFIED * @run main compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar * -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so - * -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=SelfChangedCDS.jsa + * -XX:SharedArchiveFile=SelfChangedCDS.jsa * -XX:+IgnoreUnrecognizedVMOptions - * -Xshare:auto -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -showversion + * -Xshare:auto -showversion * -Xlog:cds -Xlog:gc+heap+coops * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace * compiler.aot.fingerprint.Blah TEST-UNMODIFIED @@ -59,9 +59,9 @@ * compiler.aot.fingerprint.Blah TEST-MODIFIED * @run main compiler.aot.fingerprint.CDSRunner -cp SelfChangedCDS.jar * -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so - * -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=SelfChangedCDS.jsa + * -XX:SharedArchiveFile=SelfChangedCDS.jsa * -XX:+IgnoreUnrecognizedVMOptions - * -Xshare:auto -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -showversion + * -Xshare:auto -showversion * -Xlog:cds -Xlog:gc+heap+coops * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace * compiler.aot.fingerprint.Blah TEST-MODIFIED @@ -78,9 +78,9 @@ * compiler.aot.fingerprint.Blah TEST-UNMODIFIED * @run main compiler.aot.fingerprint.CDSRunner -Xmx512m -cp SelfChangedCDS.jar * -XX:+UseAOT -XX:+PrintAOT -XX:AOTLibrary=./libSelfChanged.so - * -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=SelfChangedCDS.jsa + * -XX:SharedArchiveFile=SelfChangedCDS.jsa * -XX:+IgnoreUnrecognizedVMOptions - * -Xshare:auto -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -showversion + * -Xshare:auto -showversion * -Xlog:cds -Xlog:gc+heap+coops * -Xlog:aot+class+fingerprint=trace -Xlog:aot+class+load=trace * compiler.aot.fingerprint.Blah TEST-UNMODIFIED diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java index 7a728a9b458..f0bf9c84082 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/BootAppendTests.java @@ -111,6 +111,7 @@ public class BootAppendTests { OutputAnalyzer out = CDSTestUtils.createArchiveAndCheck( "-Xbootclasspath/a:" + bootAppendJar, + "-cp", appJar, "-XX:SharedClassListFile=" + classlist.getPath()); // Make sure all the classes were successfully archived. for (String archiveClass : ARCHIVE_CLASSES) { @@ -156,8 +157,10 @@ public class BootAppendTests { .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); + String MATCH_PATTERN = ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; OutputAnalyzer out = CDSTestUtils.runWithArchive(opts); - CDSTestUtils.checkExec(out, opts, "[class,load] javax.annotation.processing.FilerException source: jrt:/java.compiler"); + out.shouldHaveExitValue(0) + .shouldNotMatch(MATCH_PATTERN); } } diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/DumpSharedDictionary.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/DumpSharedDictionary.java index 4fb681f86d2..a5bf715722f 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/DumpSharedDictionary.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/DumpSharedDictionary.java @@ -42,7 +42,6 @@ public class DumpSharedDictionary { if (args.length == 0) { // Start this process ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./DumpSharedDictionary.jsa", "-Xshare:dump"); @@ -52,7 +51,6 @@ public class DumpSharedDictionary { String testjdkPath = System.getProperty("test.jdk"); pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./DumpSharedDictionary.jsa", "-Dtest.jdk=" + testjdkPath, "-Xshare:on", "DumpSharedDictionary", "test"); diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/NonBootLoaderClasses.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/NonBootLoaderClasses.java index f52f356368d..a6b8176e3d0 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/NonBootLoaderClasses.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/NonBootLoaderClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test NonBootLoaderClasses - * @summary Test to ensure platform and app classes are not being archived + * @summary Test to ensure platform and app classes are archived when specified in classlist * @requires vm.cds * @library /test/lib * @modules java.base/jdk.internal.misc @@ -46,20 +46,21 @@ public class NonBootLoaderClasses { CDSTestUtils.makeClassList(classes).getPath(); String archiveName = "NonBootLoaderClasses.jsa"; CDSOptions opts = (new CDSOptions()) - .addPrefix("-XX:ExtraSharedClassListFile=" + classList) + .addPrefix("-XX:ExtraSharedClassListFile=" + classList, "-cp", "\"\"") .setArchiveName(archiveName); CDSTestUtils.createArchiveAndCheck(opts); // Print the shared dictionary and inspect the output ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-cp", "\"\"", "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./" + archiveName, "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary"); OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "print-shared-archive"); if (!CDSTestUtils.isUnableToMap(out)) { out.shouldContain("archive is valid") .shouldHaveExitValue(0) // Should report success in error code. - .shouldNotContain(PLATFORM_CLASS) - .shouldNotContain(APP_CLASS); + .shouldContain(PLATFORM_CLASS.replace('/', '.')) + .shouldContain(APP_CLASS.replace('/', '.')); } } } diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/SASymbolTableTest.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/SASymbolTableTest.java index 1656ed83b07..534f597c9a8 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/SASymbolTableTest.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/SASymbolTableTest.java @@ -77,7 +77,6 @@ public class SASymbolTableTest { // (1) Launch the attachee process System.out.println("Starting LingeredApp"); List vmOpts = Arrays.asList( - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + jsaName, "-Xshare:" + flag, "-showversion"); // so we can see "sharing" in the output diff --git a/test/hotspot/jtreg/runtime/SharedArchiveFile/SharedArchiveFile.java b/test/hotspot/jtreg/runtime/SharedArchiveFile/SharedArchiveFile.java index 0387fec1028..0e4ed4aceb0 100644 --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/SharedArchiveFile.java +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/SharedArchiveFile.java @@ -42,14 +42,12 @@ import jdk.test.lib.process.OutputAnalyzer; public class SharedArchiveFile { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./SharedArchiveFile.jsa", "-Xshare:dump"); OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "SharedArchiveFile"); CDSTestUtils.checkDump(out); pb = ProcessTools.createJavaProcessBuilder(true, - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./SharedArchiveFile.jsa", "-Xshare:on", "-version"); out = CDSTestUtils.executeAndLog(pb, "SharedArchiveFile"); diff --git a/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java b/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java index f2ea456ee70..4ae0b280be9 100644 --- a/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java +++ b/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java @@ -24,7 +24,7 @@ /* * @test - * @summary AppCDS handling of directories in -cp + * @summary Handling of directories in -cp is based on the classlist * @requires vm.cds * @library /test/lib * @run main DirClasspathTest @@ -45,10 +45,14 @@ public class DirClasspathTest { File emptydir = new File(dir, "emptydir"); emptydir.mkdir(); + ///////////////////////////////////////////////////////////////// + // The classlist only contains boot class in following test cases + ///////////////////////////////////////////////////////////////// + String bootClassList[] = {"java/lang/Object"}; + // Empty dir in -cp: should be OK OutputAnalyzer output; - String classList[] = {"java/lang/Object"}; - output = TestCommon.dump(emptydir.getPath(), classList, "-Xlog:class+path=info"); + output = TestCommon.dump(emptydir.getPath(), bootClassList, "-Xlog:class+path=info"); TestCommon.checkDump(output); // Long path to empty dir in -cp: should be OK @@ -65,19 +69,32 @@ public class DirClasspathTest { longDir.mkdir(); File subDir = new File(longDir, "subdir"); subDir.mkdir(); - output = TestCommon.dump(subDir.getPath(), classList, "-Xlog:class+path=info"); + output = TestCommon.dump(subDir.getPath(), bootClassList, "-Xlog:class+path=info"); TestCommon.checkDump(output); - // Non-empty dir in -cp: should fail + // Non-empty dir in -cp: should be OK //

is not empty because it has at least one subdirectory, i.e., - output = TestCommon.dump(dir.getPath(), classList, "-Xlog:class+path=info"); - output.shouldNotHaveExitValue(0); - output.shouldContain("CDS allows only empty directories in archived classpaths"); + output = TestCommon.dump(dir.getPath(), bootClassList, "-Xlog:class+path=info"); + TestCommon.checkDump(output); - // Long path to non-empty dir in -cp: should fail + // Long path to non-empty dir in -cp: should be OK // is not empty because it has at least one subdirectory, i.e., - output = TestCommon.dump(longDir.getPath(), classList, "-Xlog:class+path=info"); + output = TestCommon.dump(longDir.getPath(), bootClassList, "-Xlog:class+path=info"); + TestCommon.checkDump(output); + + ///////////////////////////////////////////////////////////////// + // The classlist contains non-boot class in following test cases + ///////////////////////////////////////////////////////////////// + String appClassList[] = {"java/lang/Object", "com/sun/tools/javac/Main"}; + + // Non-empty dir in -cp: should report error + output = TestCommon.dump(dir.getPath(), appClassList, "-Xlog:class+path=info"); output.shouldNotHaveExitValue(0); - output.shouldContain("CDS allows only empty directories in archived classpaths"); + output.shouldContain("Cannot have non-empty directory in paths"); + + // Long path to non-empty dir in -cp: should report error + output = TestCommon.dump(longDir.getPath(), appClassList, "-Xlog:class+path=info"); + output.shouldNotHaveExitValue(0); + output.shouldContain("Cannot have non-empty directory in paths"); } } diff --git a/test/hotspot/jtreg/runtime/appcds/DumpClassList.java b/test/hotspot/jtreg/runtime/appcds/DumpClassList.java index ab6d045f7e5..f112173ecdd 100644 --- a/test/hotspot/jtreg/runtime/appcds/DumpClassList.java +++ b/test/hotspot/jtreg/runtime/appcds/DumpClassList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,7 +92,6 @@ public class DumpClassList { output = TestCommon.createArchive(appJar, appClass, "-Xbootclasspath/a:" + appendJar, - "-XX:+UnlockDiagnosticVMOptions", "-Xlog:class+load", "-XX:SharedClassListFile=" + classList); TestCommon.checkDump(output) diff --git a/test/hotspot/jtreg/runtime/appcds/GraalWithLimitedMetaspace.java b/test/hotspot/jtreg/runtime/appcds/GraalWithLimitedMetaspace.java index 1cc230f33fa..9b2d560c73d 100644 --- a/test/hotspot/jtreg/runtime/appcds/GraalWithLimitedMetaspace.java +++ b/test/hotspot/jtreg/runtime/appcds/GraalWithLimitedMetaspace.java @@ -94,7 +94,6 @@ public class GraalWithLimitedMetaspace { "-XX:+EagerJVMCI", "-cp", TESTJAR, - "-XX:+UseAppCDS", TESTNAME, TEST_OUT)); @@ -117,7 +116,6 @@ public class GraalWithLimitedMetaspace { TestCommon.makeCommandLineForAppCDS( "-cp", TESTJAR, - "-XX:+UseAppCDS", "-XX:SharedClassListFile=" + CLASSLIST_FILE, "-XX:SharedArchiveFile=" + ARCHIVE_FILE, "-Xlog:cds", diff --git a/test/hotspot/jtreg/runtime/appcds/MismatchedUseAppCDS.java b/test/hotspot/jtreg/runtime/appcds/MismatchedUseAppCDS.java index 9b5004396a2..4c53e948455 100644 --- a/test/hotspot/jtreg/runtime/appcds/MismatchedUseAppCDS.java +++ b/test/hotspot/jtreg/runtime/appcds/MismatchedUseAppCDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ public class MismatchedUseAppCDS { "-XX:-UseAppCDS", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "CheckIfShared", "false"); + "CheckIfShared", "true"); TestCommon.checkExec(output); // (2): dump with -XX:-UseAppCDS, but run with -XX:+UseAppCDS @@ -74,7 +74,7 @@ public class MismatchedUseAppCDS { "-XX:+UseAppCDS", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "CheckIfShared", "false"); + "CheckIfShared", "true"); TestCommon.checkExec(output); } } diff --git a/test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java b/test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java index d7c87619a1e..2e39eeec099 100644 --- a/test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java +++ b/test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test - * @summary If -Djava.system.class.loader=xxx is specified in command-line, disable UseAppCDS + * @summary If -Djava.system.class.loader=xxx is specified in command-line, disable archived non-system classes * @requires vm.cds * @library /test/lib * @modules java.base/jdk.internal.misc @@ -46,7 +46,7 @@ public class SpecifySysLoaderProp { String jarFileName = "sysloader.jar"; String appJar = TestCommon.getTestJar(jarFileName); TestCommon.testDump(appJar, TestCommon.list("ReportMyLoader")); - String warning = "VM warning: UseAppCDS is disabled because the java.system.class.loader property is specified"; + String warning = "VM warning: Archived non-system classes are disabled because the java.system.class.loader property is specified"; // (0) Baseline. Do not specify -Djava.system.class.loader @@ -70,7 +70,7 @@ public class SpecifySysLoaderProp { }); // (2) Try to execute the archive with -Djava.system.class.loader=TestClassLoader, - // it should run, but AppCDS should be disabled + // it should run, but archived non-system classes should be disabled TestCommon.run( "-verbose:class", "-cp", appJar, diff --git a/test/hotspot/jtreg/runtime/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/appcds/TestCommon.java index bee1e4a9c0a..b15ea0c8a91 100644 --- a/test/hotspot/jtreg/runtime/appcds/TestCommon.java +++ b/test/hotspot/jtreg/runtime/appcds/TestCommon.java @@ -109,18 +109,8 @@ public class TestCommon extends CDSTestUtils { return createArchive(opts); } - // If you use -XX:+UseAppCDS or -XX:-UseAppCDS in your JVM command-line, call this method - // to wrap the arguments. On commercial builds, -XX:+UnlockCommercialFeatures will be - // prepended to the command-line. See JDK-8193664. public static String[] makeCommandLineForAppCDS(String... args) throws Exception { - if (BuildHelper.isCommercialBuild()) { - String[] newArgs = new String[args.length + 1]; - newArgs[0] = "-XX:+UnlockCommercialFeatures"; - System.arraycopy(args, 0, newArgs, 1, args.length); - return newArgs; - } else { - return args; - } + return args; } // Create AppCDS archive using appcds options @@ -143,7 +133,6 @@ public class TestCommon extends CDSTestUtils { cmd.add("-Xshare:dump"); cmd.add("-Xlog:cds,cds+hashtables"); - cmd.add("-XX:+UseAppCDS"); cmd.add("-XX:ExtraSharedClassListFile=" + classList.getPath()); if (opts.archiveName == null) @@ -168,7 +157,6 @@ public class TestCommon extends CDSTestUtils { for (String p : opts.prefix) cmd.add(p); cmd.add("-Xshare:" + opts.xShareMode); - cmd.add("-XX:+UseAppCDS"); cmd.add("-showversion"); cmd.add("-XX:SharedArchiveFile=" + getCurrentArchiveName()); cmd.add("-Dtest.timeout.factor=" + timeoutFactor); diff --git a/test/hotspot/jtreg/runtime/appcds/VerifierTest.java b/test/hotspot/jtreg/runtime/appcds/VerifierTest.java index bfdfe2566ca..f9a07234cd7 100644 --- a/test/hotspot/jtreg/runtime/appcds/VerifierTest.java +++ b/test/hotspot/jtreg/runtime/appcds/VerifierTest.java @@ -243,7 +243,6 @@ public class VerifierTest implements Opcodes { if (!dump_setting.equals(prev_dump_setting)) { OutputAnalyzer dumpOutput = TestCommon.dump( jar, appClasses, dump_setting, - "-XX:+UnlockDiagnosticVMOptions", // FIXME: the following options are for working around a GC // issue - assert failure when dumping archive with the -Xverify:all "-Xms256m", diff --git a/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsBasic.java b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsBasic.java index 91f6510ebdb..d6049014dbd 100644 --- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsBasic.java +++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsBasic.java @@ -48,7 +48,6 @@ public class SharedStringsBasic { ProcessBuilder dumpPb = ProcessTools.createJavaProcessBuilder(true, TestCommon.makeCommandLineForAppCDS( - "-XX:+UseAppCDS", "-cp", appJar, "-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile, "-XX:SharedArchiveFile=./SharedStringsBasic.jsa", @@ -61,7 +60,6 @@ public class SharedStringsBasic { ProcessBuilder runPb = ProcessTools.createJavaProcessBuilder(true, TestCommon.makeCommandLineForAppCDS( - "-XX:+UseAppCDS", "-cp", appJar, "-XX:SharedArchiveFile=./SharedStringsBasic.jsa", "-Xshare:auto", diff --git a/test/hotspot/jtreg/runtime/appcds/sharedStrings/SysDictCrash.java b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SysDictCrash.java index a5cc200596c..3aa9d5467ca 100644 --- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/SysDictCrash.java +++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SysDictCrash.java @@ -44,7 +44,6 @@ public class SysDictCrash { ProcessBuilder dumpPb = ProcessTools.createJavaProcessBuilder(true, TestCommon.makeCommandLineForAppCDS( "-XX:+UseG1GC", "-XX:MaxRAMPercentage=12.5", - "-XX:+UseAppCDS", "-cp", ".", "-XX:SharedBaseAddress=0", "-XX:SharedArchiveFile=./SysDictCrash.jsa", "-Xshare:dump", @@ -55,7 +54,6 @@ public class SysDictCrash { ProcessBuilder runPb = ProcessTools.createJavaProcessBuilder(true, TestCommon.makeCommandLineForAppCDS( "-XX:+UseG1GC", "-XX:MaxRAMPercentage=12.5", - "-XX:+UseAppCDS", "-XX:SharedArchiveFile=./SysDictCrash.jsa", "-Xshare:on", "-version")); diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index dc21b9fc3d2..11fb559cd98 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -247,7 +247,6 @@ public class CDSTestUtils { cmd.add("-Xshare:dump"); cmd.add("-Xlog:cds,cds+hashtables"); - cmd.add("-XX:+UnlockDiagnosticVMOptions"); if (opts.archiveName == null) opts.archiveName = getDefaultArchiveName(); cmd.add("-XX:SharedArchiveFile=./" + opts.archiveName); @@ -389,7 +388,6 @@ public class CDSTestUtils { for (String p : opts.prefix) cmd.add(p); cmd.add("-Xshare:" + opts.xShareMode); - cmd.add("-XX:+UnlockDiagnosticVMOptions"); cmd.add("-Dtest.timeout.factor=" + TestTimeoutFactor); if (opts.archiveName == null) From 3544f8902a07dfd85ae5a4e0da80b23bbde32014 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Mon, 30 Apr 2018 17:50:05 -0400 Subject: [PATCH 087/102] 8202452: Delete test files missed from commit for 8193213&8182731 Deleted outdated tests. Reviewed-by: dholmes --- .../runtime/appcds/SharedArchiveFile.java | 82 ------- .../jtreg/runtime/appcds/UseAppCDS.java | 232 ------------------ 2 files changed, 314 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/appcds/SharedArchiveFile.java delete mode 100644 test/hotspot/jtreg/runtime/appcds/UseAppCDS.java diff --git a/test/hotspot/jtreg/runtime/appcds/SharedArchiveFile.java b/test/hotspot/jtreg/runtime/appcds/SharedArchiveFile.java deleted file mode 100644 index 5ae838f4a82..00000000000 --- a/test/hotspot/jtreg/runtime/appcds/SharedArchiveFile.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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 The diagnostic option, -XX:SharedArchiveFile can be unlocked using -XX:+UseAppCDS - * @requires vm.cds - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * jdk.jartool/sun.tools.jar - * @compile test-classes/Hello.java - * @run main SharedArchiveFile - */ - -import jdk.test.lib.Platform; -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import java.util.Properties; - -public class SharedArchiveFile { - public static void main(String[] args) throws Exception { - boolean isProduct = !Platform.isDebugBuild(); - String appJar = JarBuilder.getOrCreateHelloJar(); - - // 1) Using -XX:SharedArchiveFile without -XX:+UseAppCDS should fail - // on product binary without -XX:+UnlockDiagnosticVMOptions. - if (isProduct) { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, - "-XX:SharedArchiveFile=./SharedArchiveFile.jsa", "-Xshare:dump"); - OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "dump"); - out.shouldContain("Error: VM option 'SharedArchiveFile' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); - } - - // 2) Dumping with -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile - // should always succeed. - CDSTestUtils.createArchive("-XX:+UnlockDiagnosticVMOptions") - .shouldContain("Dumping"); - - // 3) Using -XX:SharedArchiveFile with -XX:+UseAppCDS should work - // on product binary by default. - OutputAnalyzer output3 = TestCommon.dump(appJar, TestCommon.list("Hello")); - output3.shouldContain("Dumping"); - output3 = TestCommon.exec(appJar, "Hello"); - TestCommon.checkExec(output3, "Hello World"); - - // 4) Using -XX:+UseAppCDS should not affect other diagnostic flags, - // such as LogEvents - OutputAnalyzer output4 = TestCommon.exec(appJar, "-XX:+LogEvents", "Hello"); - if (isProduct) { - output4.shouldContain("Error: VM option 'LogEvents' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); - } else { - TestCommon.checkExec(output4, "Hello World"); - } - - // 5) 8066921 - Extra -XX:+UseAppCDS - TestCommon.testDump(appJar, TestCommon.list("Hello"), "-XX:+UseAppCDS"); - OutputAnalyzer output5 = TestCommon.exec(appJar, "-XX:+UseAppCDS", "Hello"); - TestCommon.checkExec(output5); - } -} diff --git a/test/hotspot/jtreg/runtime/appcds/UseAppCDS.java b/test/hotspot/jtreg/runtime/appcds/UseAppCDS.java deleted file mode 100644 index e3f4fbcc4b9..00000000000 --- a/test/hotspot/jtreg/runtime/appcds/UseAppCDS.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * @test - * @summary Testing use of UseAppCDS flag - * @requires vm.cds - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * jdk.jartool/sun.tools.jar - * @build UseAppCDS_Test - * @run main UseAppCDS - */ - -import jdk.test.lib.JDKToolLauncher; -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -import java.util.ArrayList; -import java.util.List; -import java.io.*; - -public class UseAppCDS { - - // Class UseAppCDS_Test is loaded by the App loader - - static final String TEST_OUT = "UseAppCDS_Test.main--executed"; - - private static final String TESTJAR = "./test.jar"; - private static final String TESTNAME = "UseAppCDS_Test"; - private static final String TESTCLASS = TESTNAME + ".class"; - - private static final String CLASSES_DIR = System.getProperty("test.classes", "."); - private static final String CLASSLIST_FILE = "./UseAppCDS.classlist"; - private static final String ARCHIVE_FILE = "./shared.jsa"; - private static final String BOOTCLASS = "java.lang.Class"; - - public static void main(String[] args) throws Exception { - - // First create a jar file for the application "test" class - JDKToolLauncher jar = JDKToolLauncher.create("jar") - .addToolArg("-cf") - .addToolArg(TESTJAR) - .addToolArg("-C") - .addToolArg(CLASSES_DIR) - .addToolArg(TESTCLASS); - - ProcessBuilder pb = new ProcessBuilder(jar.getCommand()); - TestCommon.executeAndLog(pb, "jar01").shouldHaveExitValue(0); - - pb = new ProcessBuilder(jar.getCommand()); - TestCommon.executeAndLog(pb, "jar02").shouldHaveExitValue(0); - - // In all tests the BOOTCLASS should be loaded/dumped/used - - // Test 1: No AppCDS - dumping loaded classes excludes the "test" classes - dumpLoadedClasses(false, new String[] { BOOTCLASS }, - new String[] { TESTNAME }); - - // Test 2: AppCDS - dumping loaded classes includes "test" classes - dumpLoadedClasses(true, new String[] { BOOTCLASS, TESTNAME }, - new String[0]); - - // Next tests rely on the classlist we just dumped - - // Test 3: No AppCDS - "test" classes in classlist ignored when dumping - // Although AppCDS isn't used, all classes will be found during dumping - // after the fix for JDK-8193434. Classes which are not in the boot - // loader dictionary will not be saved into the archive. - dumpArchive(false, new String[] { BOOTCLASS }, - new String[0]); - - // Test 4: AppCDS - "test" classes in classlist are dumped - dumpArchive(true, new String[] { BOOTCLASS, TESTNAME }, - new String[0]); - - // Next tests rely on the archive we just dumped - - // Test 5: No AppCDS - Using archive containing "test" classes ignores them - useArchive(false, new String[] { BOOTCLASS }, - new String[] { TESTNAME }); - - // Test 6: AppCDS - Using archive containing "test" classes loads them - useArchive(true, new String[] { BOOTCLASS, TESTNAME }, - new String[0]); - } - - public static List toClassNames(String filename) throws IOException { - ArrayList classes = new ArrayList<>(); - try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename)))) { - for (; ; ) { - String line = br.readLine(); - if (line == null) { - break; - } - classes.add(line.replaceAll("/", ".")); - } - } - return classes; - } - - static void dumpLoadedClasses(boolean useAppCDS, String[] expectedClasses, - String[] unexpectedClasses) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, - TestCommon.makeCommandLineForAppCDS( - "-XX:DumpLoadedClassList=" + CLASSLIST_FILE, - "-cp", - TESTJAR, - useAppCDS ? "-XX:+UseAppCDS" : "-XX:-UseAppCDS", - TESTNAME, - TEST_OUT)); - - OutputAnalyzer output = TestCommon.executeAndLog(pb, "dump-loaded-classes") - .shouldHaveExitValue(0).shouldContain(TEST_OUT); - - List dumpedClasses = toClassNames(CLASSLIST_FILE); - - for (String clazz : expectedClasses) { - if (!dumpedClasses.contains(clazz)) { - throw new RuntimeException(clazz + " missing in " + - CLASSLIST_FILE); - } - } - for (String clazz : unexpectedClasses) { - if (dumpedClasses.contains(clazz)) { - throw new RuntimeException("Unexpectedly found " + clazz + - " in " + CLASSLIST_FILE); - } - } - } - - static void dumpArchive(boolean useAppCDS, String[] expectedClasses, - String[] unexpectedClasses) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, - TestCommon.makeCommandLineForAppCDS( - useAppCDS ? "-XX:-UnlockDiagnosticVMOptions" : - "-XX:+UnlockDiagnosticVMOptions", - "-cp", - TESTJAR, - useAppCDS ? "-XX:+UseAppCDS" : "-XX:-UseAppCDS", - "-XX:SharedClassListFile=" + CLASSLIST_FILE, - "-XX:SharedArchiveFile=" + ARCHIVE_FILE, - "-Xlog:cds", - "-Xshare:dump")); - - OutputAnalyzer output = TestCommon.executeAndLog(pb, "dump-archive") - .shouldHaveExitValue(0); - - for (String clazz : expectedClasses) { - String failed = "Preload Warning: Cannot find " + clazz; - output.shouldNotContain(failed); - } - for (String clazz : unexpectedClasses) { - String failed = "Preload Warning: Cannot find " + clazz; - output.shouldContain(failed); - } - } - - static void useArchive(boolean useAppCDS, String[] expectedClasses, - String[] unexpectedClasses) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, - TestCommon.makeCommandLineForAppCDS( - useAppCDS ? "-XX:-UnlockDiagnosticVMOptions" : - "-XX:+UnlockDiagnosticVMOptions", - "-cp", - TESTJAR, - useAppCDS ? "-XX:+UseAppCDS" : "-XX:-UseAppCDS", - "-XX:SharedArchiveFile=" + ARCHIVE_FILE, - "-verbose:class", - "-Xshare:on", - TESTNAME, - TEST_OUT)); - - OutputAnalyzer output = TestCommon.executeAndLog(pb, "use-archive"); - if (CDSTestUtils.isUnableToMap(output)) - System.out.println("Unable to map: test case skipped"); - else - output.shouldHaveExitValue(0).shouldContain(TEST_OUT); - - // Quote the class name in the regex as it may contain $ - String prefix = ".class,load. "; - String archive_suffix = ".*source: shared objects file.*"; - String jar_suffix = ".*source: .*\\.jar"; - - for (String clazz : expectedClasses) { - String pattern = prefix + clazz + archive_suffix; - try { - output.shouldMatch(pattern); - } catch (Exception e) { - TestCommon.checkCommonExecExceptions(output, e); - } - } - - for (String clazz : unexpectedClasses) { - String pattern = prefix + clazz + archive_suffix; - try { - output.shouldNotMatch(pattern); - } catch (Exception e) { - TestCommon.checkCommonExecExceptions(output, e); - } - pattern = prefix + clazz + jar_suffix; - try { - output.shouldMatch(pattern); - } catch (Exception e) { - TestCommon.checkCommonExecExceptions(output, e); - } - } - } -} From 1298458a1de9c9e7e39b680297a7d45420cacba6 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 30 Apr 2018 20:29:19 -0400 Subject: [PATCH 088/102] 8202399: [C1] LIRGenerator::do_CheckCast needs to exclude is_invokespecial_receiver_check() when using PatchAlot Reviewed-by: kvn --- src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp | 2 +- src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp | 2 +- src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp | 2 +- src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp | 2 +- src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp | 2 +- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index caadd0fb908..8f4e0200187 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -1187,7 +1187,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { LIRItem obj(x->obj(), this); CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { // must do this before locking the destination register as an oop register, // and before the obj is loaded (the latter is for deoptimization) patching_info = state_for(x, x->state_before()); diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index c03eb66281f..e298140724c 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -1335,7 +1335,7 @@ void LIRGenerator::do_BlockBegin(BlockBegin* x) { void LIRGenerator::do_CheckCast(CheckCast* x) { LIRItem obj(x->obj(), this); CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { patching_info = state_for(x, x->state_before()); } diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index 4fadd0c9961..6b1eed703b2 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -1068,7 +1068,7 @@ void LIRGenerator::do_BlockBegin(BlockBegin* x) { void LIRGenerator::do_CheckCast(CheckCast* x) { LIRItem obj(x->obj(), this); CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { // Must do this before locking the destination register as // an oop register, and before the obj is loaded (so x->obj()->item() // is valid for creating a debug info location). diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index fc5a2d6eac5..1b31cad3c2a 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -875,7 +875,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { LIRItem obj(x->obj(), this); CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { // Must do this before locking the destination register as an oop register, // and before the obj is loaded (the latter is for deoptimization). patching_info = state_for (x, x->state_before()); diff --git a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp index 129e1899e19..9992e114940 100644 --- a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp @@ -1124,7 +1124,7 @@ void LIRGenerator::do_BlockBegin(BlockBegin* x) { void LIRGenerator::do_CheckCast(CheckCast* x) { LIRItem obj(x->obj(), this); CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { // must do this before locking the destination register as an oop register, // and before the obj is loaded (so x->obj()->item() is valid for creating a debug info location) patching_info = state_for(x, x->state_before()); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 5e4e8e21536..d68c9b85c4f 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -1314,7 +1314,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { LIRItem obj(x->obj(), this); CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { // must do this before locking the destination register as an oop register, // and before the obj is loaded (the latter is for deoptimization) patching_info = state_for(x, x->state_before()); From 08855df46a33ada6ce2abc124c32a5f4c231b680 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Mon, 30 Apr 2018 18:10:24 -0700 Subject: [PATCH 089/102] 8199643: [TESTBUG] Open source common VM testbase code Reviewed-by: vlivanov, erikj, mseledtsov, gthornbr --- make/test/JtregNativeHotspot.gmk | 15 + test/hotspot/jtreg/vmTestbase/ExecDriver.java | 170 + .../vmTestbase/PropertyResolvingWrapper.java | 138 + test/hotspot/jtreg/vmTestbase/README.md | 10 + .../nsk/share/AbstractGoldChecker.java | 164 + .../vmTestbase/nsk/share/ArgumentParser.java | 507 ++ .../vmTestbase/nsk/share/ClassFileFinder.java | 52 + .../vmTestbase/nsk/share/ClassUnloader.java | 352 ++ .../jtreg/vmTestbase/nsk/share/Consts.java | 47 + .../nsk/share/CustomClassLoader.java | 150 + .../jtreg/vmTestbase/nsk/share/Debug.java | 45 + .../vmTestbase/nsk/share/Denotation.java | 139 + .../nsk/share/DummyClassLoader.java | 51 + .../jtreg/vmTestbase/nsk/share/Failure.java | 46 + .../jtreg/vmTestbase/nsk/share/FileUtils.java | 71 + .../vmTestbase/nsk/share/Finalizable.java | 43 + .../nsk/share/FinalizableObject.java | 50 + .../jtreg/vmTestbase/nsk/share/Finalizer.java | 133 + .../vmTestbase/nsk/share/GoldChecker.java | 71 + .../jtreg/vmTestbase/nsk/share/Grep.java | 103 + .../jtreg/vmTestbase/nsk/share/Harakiri.java | 175 + .../vmTestbase/nsk/share/IORedirector.java | 142 + .../jtreg/vmTestbase/nsk/share/JVMDITools.c | 173 + .../jtreg/vmTestbase/nsk/share/JVMDITools.h | 33 + .../jtreg/vmTestbase/nsk/share/JVMTIagent.c | 1276 +++++ .../vmTestbase/nsk/share/LocalProcess.java | 177 + .../jtreg/vmTestbase/nsk/share/Log.java | 736 +++ .../vmTestbase/nsk/share/NativeUtils.java | 31 + .../nsk/share/ObjectInstancesManager.java | 232 + .../jtreg/vmTestbase/nsk/share/Oddity.java | 36 + .../jtreg/vmTestbase/nsk/share/Pair.java | 42 + .../jtreg/vmTestbase/nsk/share/Paragrep.java | 176 + .../vmTestbase/nsk/share/PrintProperties.java | 54 + .../jtreg/vmTestbase/nsk/share/RASagent.java | 376 ++ .../hotspot/jtreg/vmTestbase/nsk/share/README | 128 + .../vmTestbase/nsk/share/ReferringObject.java | 265 + .../nsk/share/ReferringObjectSet.java | 77 + .../nsk/share/StringGoldChecker.java | 37 + .../jtreg/vmTestbase/nsk/share/TestBug.java | 46 + .../vmTestbase/nsk/share/TestFailure.java | 41 + .../vmTestbase/nsk/share/TestJNIError.java | 32 + .../vmTestbase/nsk/share/TimeoutHandler.java | 60 + .../nsk/share/TreeNodesDenotation.java | 175 + .../jtreg/vmTestbase/nsk/share/Wicket.java | 229 + .../nsk/share/aod/AODRunnerArgParser.java | 127 + .../nsk/share/aod/AODTargetArgParser.java | 83 + .../nsk/share/aod/AODTestRunner.java | 186 + .../nsk/share/aod/AbstractJarAgent.java | 257 + .../nsk/share/aod/AgentInformation.java | 68 + .../nsk/share/aod/AgentsAttacher.java | 137 + .../nsk/share/aod/DummyTargetApplication.java | 73 + .../nsk/share/aod/ProcessExecutor.java | 251 + .../aod/TargetApplicationWaitingAgents.java | 400 ++ .../jtreg/vmTestbase/nsk/share/aod/Utils.java | 95 + .../jtreg/vmTestbase/nsk/share/aod/aod.c | 288 + .../jtreg/vmTestbase/nsk/share/aod/aod.h | 83 + .../ClassPathNonDelegatingClassLoader.java | 80 + .../classload/GeneratingClassLoader.java | 185 + .../nsk/share/classload/TemplateClass.java | 27 + .../vmTestbase/nsk/share/gc/Algorithms.java | 206 + .../vmTestbase/nsk/share/gc/AllDiag.java | 53 + .../nsk/share/gc/AllMemoryObject.java | 56 + .../nsk/share/gc/ArgumentHandler.java | 363 ++ .../jtreg/vmTestbase/nsk/share/gc/Cell.java | 43 + .../nsk/share/gc/CircularLinkedList.java | 74 + .../vmTestbase/nsk/share/gc/ClassChain.java | 5035 +++++++++++++++++ .../vmTestbase/nsk/share/gc/FinDiag.java | 53 + .../nsk/share/gc/FinMemoryObject.java | 70 + .../nsk/share/gc/FinMemoryObject1.java | 60 + .../jtreg/vmTestbase/nsk/share/gc/GC.java | 116 + .../vmTestbase/nsk/share/gc/GCParams.java | 103 + .../nsk/share/gc/GCParamsAware.java | 31 + .../vmTestbase/nsk/share/gc/GCTestBase.java | 41 + .../vmTestbase/nsk/share/gc/IndexPair.java | 61 + .../nsk/share/gc/LinkedMemoryObject.java | 69 + .../jtreg/vmTestbase/nsk/share/gc/Matrix.java | 68 + .../jtreg/vmTestbase/nsk/share/gc/Memory.java | 513 ++ .../vmTestbase/nsk/share/gc/MemoryObject.java | 50 + .../nsk/share/gc/NonbranchyTree.java | 206 + .../vmTestbase/nsk/share/gc/OOMStress.java | 30 + .../nsk/share/gc/ThreadedGCTest.java | 76 + .../nsk/share/gc/TwoFieldsObject.java | 51 + .../nsk/share/gc/classes/Classes.java | 5024 ++++++++++++++++ .../nsk/share/gc/gp/DerivedProducer.java | 52 + .../share/gc/gp/DerivedStrategyProducer.java | 43 + .../nsk/share/gc/gp/GarbageProducer.java | 45 + .../share/gc/gp/GarbageProducer1Aware.java | 31 + .../nsk/share/gc/gp/GarbageProducerAware.java | 31 + .../nsk/share/gc/gp/GarbageProducers.java | 90 + .../nsk/share/gc/gp/GarbageUtils.java | 398 ++ .../nsk/share/gc/gp/MemoryStrategy.java | 134 + .../nsk/share/gc/gp/MemoryStrategyAware.java | 31 + .../nsk/share/gc/gp/RandomProducer.java | 46 + .../share/gc/gp/array/ArrayOfProducer.java | 63 + .../nsk/share/gc/gp/array/ArrayProducer.java | 57 + .../gc/gp/array/BooleanArrayProducer.java | 44 + .../share/gc/gp/array/ByteArrayProducer.java | 44 + .../share/gc/gp/array/CharArrayProducer.java | 44 + .../gc/gp/array/DoubleArrayProducer.java | 43 + .../share/gc/gp/array/FloatArrayProducer.java | 43 + .../share/gc/gp/array/IntArrayProducer.java | 44 + .../share/gc/gp/array/LongArrayProducer.java | 44 + .../gc/gp/array/ObjectArrayProducer.java | 40 + .../share/gc/gp/array/ShortArrayProducer.java | 44 + .../gp/classload/GeneratedClassProducer.java | 83 + .../gc/gp/list/CircularListProducer.java | 52 + .../share/gc/gp/list/LinearListProducer.java | 52 + .../gc/gp/misc/HashedGarbageProducer.java | 65 + .../nsk/share/gc/gp/misc/TraceProducer.java | 49 + .../gc/gp/misc/TwoFieldsObjectProducer.java | 47 + .../gc/gp/obj/AllMemoryObjectProducer.java | 36 + .../gc/gp/obj/FinMemoryObject1Producer.java | 36 + .../gc/gp/obj/FinMemoryObjectProducer.java | 36 + .../share/gc/gp/obj/MemoryObjectProducer.java | 36 + .../gc/gp/string/InternedStringProducer.java | 47 + .../gc/gp/string/RandomStringProducer.java | 62 + .../gc/gp/string/SimpleStringProducer.java | 46 + .../gc/gp/tree/NonbranchyTreeProducer.java | 59 + .../share/gc/lock/CriticalSectionLocker.java | 127 + .../gc/lock/CriticalSectionObjectLocker.java | 41 + .../gc/lock/CriticalSectionTimedLocker.java | 65 + .../vmTestbase/nsk/share/gc/lock/Locker.java | 63 + .../nsk/share/gc/lock/LockerUtils.java | 62 + .../vmTestbase/nsk/share/gc/lock/Lockers.java | 30 + .../nsk/share/gc/lock/LockersAware.java | 31 + .../nsk/share/gc/lock/MultiLocker.java | 66 + .../gc/lock/jni/BooleanArrayCriticalLocker.c | 80 + .../lock/jni/BooleanArrayCriticalLocker.java | 53 + .../gc/lock/jni/ByteArrayCriticalLocker.c | 79 + .../gc/lock/jni/ByteArrayCriticalLocker.java | 53 + .../gc/lock/jni/CharArrayCriticalLocker.c | 80 + .../gc/lock/jni/CharArrayCriticalLocker.java | 53 + .../gc/lock/jni/DoubleArrayCriticalLocker.c | 80 + .../lock/jni/DoubleArrayCriticalLocker.java | 53 + .../gc/lock/jni/FloatArrayCriticalLocker.c | 80 + .../gc/lock/jni/FloatArrayCriticalLocker.java | 53 + .../gc/lock/jni/IntArrayCriticalLocker.c | 80 + .../gc/lock/jni/IntArrayCriticalLocker.java | 53 + .../nsk/share/gc/lock/jni/JNILockers.java | 52 + .../gc/lock/jni/LongArrayCriticalLocker.c | 80 + .../gc/lock/jni/LongArrayCriticalLocker.java | 53 + .../gc/lock/jni/ShortArrayCriticalLocker.c | 80 + .../gc/lock/jni/ShortArrayCriticalLocker.java | 53 + .../share/gc/lock/jni/StringCriticalLocker.c | 80 + .../gc/lock/jni/StringCriticalLocker.java | 56 + .../share/gc/lock/jniref/JNIGlobalRefLocker.c | 70 + .../gc/lock/jniref/JNIGlobalRefLocker.java | 46 + .../gc/lock/jniref/JNIGlobalRefLockers.java | 34 + .../share/gc/lock/jniref/JNILocalRefLocker.c | 70 + .../gc/lock/jniref/JNILocalRefLocker.java | 46 + .../gc/lock/jniref/JNILocalRefLockers.java | 34 + .../nsk/share/gc/lock/jniref/JNIRefLocker.c | 74 + .../share/gc/lock/jniref/JNIRefLocker.java | 47 + .../share/gc/lock/jniref/JNIRefLockers.java | 34 + .../gc/lock/jniref/JNIWeakGlobalRefLocker.c | 70 + .../lock/jniref/JNIWeakGlobalRefLocker.java | 46 + .../lock/jniref/JNIWeakGlobalRefLockers.java | 34 + .../share/gc/lock/jvmti/JVMTIAllocLocker.c | 64 + .../share/gc/lock/jvmti/JVMTIAllocLocker.java | 58 + .../gc/lock/jvmti/JVMTIAllocLockers.java | 33 + .../nsk/share/gc/lock/malloc/MallocLocker.c | 47 + .../share/gc/lock/malloc/MallocLocker.java | 57 + .../share/gc/lock/malloc/MallocLockers.java | 34 + .../vmTestbase/nsk/share/gc/tree/Tree.java | 59 + .../nsk/share/gc/tree/TreeNode.java | 210 + .../nsk/share/jdi/AbstractJDIDebuggee.java | 42 + .../nsk/share/jdi/ArgumentHandler.java | 653 +++ .../vmTestbase/nsk/share/jdi/Binder.java | 1273 +++++ .../nsk/share/jdi/ConnectorTest.java | 238 + .../vmTestbase/nsk/share/jdi/Debugee.java | 648 +++ .../nsk/share/jdi/DebuggeeEventData.java | 93 + .../nsk/share/jdi/DebuggerEventData.java | 148 + .../nsk/share/jdi/EventFilters.java | 342 ++ .../nsk/share/jdi/EventHandler.java | 569 ++ .../nsk/share/jdi/EventTestTemplates.java | 457 ++ .../share/jdi/ForceEarlyReturnDebugger.java | 81 + .../nsk/share/jdi/HeapwalkingDebuggee.java | 231 + .../nsk/share/jdi/HeapwalkingDebugger.java | 196 + .../nsk/share/jdi/JDIEventsDebuggee.java | 250 + .../nsk/share/jdi/JDIEventsDebugger.java | 909 +++ .../nsk/share/jdi/MockReferenceType.java | 297 + .../nsk/share/jdi/MonitorEnterExecutor.c | 118 + .../nsk/share/jdi/MonitorEventsDebuggee.java | 523 ++ .../nsk/share/jdi/OwnedMonitorsDebuggee.java | 246 + .../nsk/share/jdi/OwnedMonitorsDebugger.java | 234 + .../nsk/share/jdi/PlugConnectors.java | 596 ++ .../nsk/share/jdi/PlugTransportService.java | 250 + .../share/jdi/SerialExecutionDebuggee.java | 138 + .../share/jdi/SerialExecutionDebugger.java | 337 ++ .../vmTestbase/nsk/share/jdi/TestClass1.java | 29 + .../vmTestbase/nsk/share/jdi/TestClass2.java | 30 + .../nsk/share/jdi/TestDebuggerType1.java | 276 + .../nsk/share/jdi/TestDebuggerType2.java | 363 ++ .../share/jdi/TestInterfaceImplementer1.java | 51 + .../vmTestbase/nsk/share/jdi/ThreadState.java | 105 + .../share/jdi/ValueConversionDebugger.java | 264 + .../nsk/share/jdi/sde/InstallSDE.java | 350 ++ .../nsk/share/jdi/sde/SDEDebuggee.java | 93 + .../nsk/share/jdi/sde/SDEDebugger.java | 1123 ++++ .../nsk/share/jdi/sde/SmapGenerator.java | 191 + .../nsk/share/jdi/sde/SmapStratum.java | 285 + .../nsk/share/jdi/sde/TestClass1.java | 62 + .../vmTestbase/nsk/share/jni/JNIreferences.c | 218 + .../jtreg/vmTestbase/nsk/share/jni/README | 61 + .../vmTestbase/nsk/share/jni/jni_tools.c | 204 + .../vmTestbase/nsk/share/jni/jni_tools.h | 174 + .../nsk/share/jpda/AbstractDebuggeeTest.java | 374 ++ .../vmTestbase/nsk/share/jpda/BindServer.java | 1888 ++++++ .../nsk/share/jpda/ConversionUtils.java | 353 ++ .../share/jpda/DebugeeArgumentHandler.java | 828 +++ .../nsk/share/jpda/DebugeeBinder.java | 758 +++ .../nsk/share/jpda/DebugeeProcess.java | 427 ++ .../jpda/ForceEarlyReturnTestThread.java | 1038 ++++ .../vmTestbase/nsk/share/jpda/IOPipe.java | 98 + .../nsk/share/jpda/SocketConnection.java | 680 +++ .../nsk/share/jpda/SocketIOPipe.java | 298 + .../nsk/share/jpda/StateTestThread.java | 161 + .../nsk/share/locks/DeadlockLocker.java | 86 + .../nsk/share/locks/DeadlockMaker.java | 161 + .../nsk/share/locks/DeadlockedThread.java | 67 + .../nsk/share/locks/JNIMonitorLocker.c | 127 + .../nsk/share/locks/JNIMonitorLocker.java | 51 + .../vmTestbase/nsk/share/locks/LockType.java | 34 + .../nsk/share/locks/LockingThread.c | 77 + .../nsk/share/locks/LockingThread.java | 637 +++ .../nsk/share/locks/MonitorLockingThread.java | 117 + .../nsk/share/locks/ReentrantLockLocker.java | 54 + .../share/locks/SynchronizedBlockLocker.java | 50 + .../share/locks/SynchronizedMethodLocker.java | 47 + .../jtreg/vmTestbase/nsk/share/log/Log.java | 111 + .../vmTestbase/nsk/share/log/LogAware.java | 37 + .../vmTestbase/nsk/share/log/LogSupport.java | 144 + .../jtreg/vmTestbase/nsk/share/native/README | 186 + .../nsk/share/native/native_thread.c | 211 + .../nsk/share/native/native_thread.h | 82 + .../nsk/share/native/native_utils.c | 47 + .../vmTestbase/nsk/share/native/nsk_list.c | 135 + .../vmTestbase/nsk/share/native/nsk_list.h | 67 + .../vmTestbase/nsk/share/native/nsk_mutex.c | 89 + .../vmTestbase/nsk/share/native/nsk_mutex.h | 61 + .../vmTestbase/nsk/share/native/nsk_tools.c | 310 + .../vmTestbase/nsk/share/native/nsk_tools.h | 211 + .../nsk/share/runner/FinRunner.java | 34 + .../vmTestbase/nsk/share/runner/GCRunner.java | 33 + .../vmTestbase/nsk/share/runner/MemDiag.java | 51 + .../nsk/share/runner/MultiRunner.java | 73 + .../nsk/share/runner/MultiRunnerAware.java | 31 + .../nsk/share/runner/RunParams.java | 268 + .../nsk/share/runner/RunParamsAware.java | 31 + .../nsk/share/runner/ThreadsRunner.java | 297 + .../nsk/share/sysdict/ClassLoadersBTree.java | 141 + .../nsk/share/sysdict/ClassLoadersChain.java | 94 + .../vmTestbase/nsk/share/test/Dumpable.java | 30 + .../nsk/share/test/ExecutionController.java | 31 + .../nsk/share/test/Initializable.java | 31 + .../nsk/share/test/LazyFormatString.java | 39 + .../nsk/share/test/LazyIntArrayToString.java | 40 + .../share/test/LazyObjectArrayToString.java | 40 + .../nsk/share/test/LocalRandom.java | 316 ++ .../nsk/share/test/StressOptions.java | 276 + .../vmTestbase/nsk/share/test/Stresser.java | 353 ++ .../jtreg/vmTestbase/nsk/share/test/Test.java | 30 + .../vmTestbase/nsk/share/test/TestBase.java | 67 + .../nsk/share/test/TestExitCode.java | 31 + .../vmTestbase/nsk/share/test/TestUtils.java | 149 + .../vmTestbase/nsk/share/test/Tests.java | 104 + .../test/timeoutwatchdog/TimeoutHandler.java | 36 + .../test/timeoutwatchdog/TimeoutWatchdog.java | 73 + .../vm/share/CommentedFileReader.java | 119 + .../jtreg/vmTestbase/vm/share/FileUtils.java | 81 + .../vm/share/InMemoryJavaCompiler.java | 125 + .../jtreg/vmTestbase/vm/share/ProcessUtils.c | 258 + .../vmTestbase/vm/share/ProcessUtils.java | 112 + .../jtreg/vmTestbase/vm/share/RandomEx.java | 89 + .../vmTestbase/vm/share/StringUtils.java | 89 + .../vmTestbase/vm/share/UnsafeAccess.java | 42 + .../vm/share/VMRuntimeEnvUtils.java | 108 + .../gc/TriggerUnloadingByFillingHeap.java | 69 + .../TriggerUnloadingByFillingMetaspace.java | 91 + .../vm/share/gc/TriggerUnloadingHelper.java | 31 + .../gc/TriggerUnloadingWithWhiteBox.java | 38 + .../vmTestbase/vm/share/libProcessUtils.c | 27 + .../vm/share/monitoring/MemoryPoolFinder.java | 66 + .../monitoring/data/MemoryManagerData.java | 61 + .../share/monitoring/data/MemoryPoolData.java | 59 + .../monitoring/data/MemoryUsageData.java | 82 + .../vm/share/options/BasicObjectFactory.java | 141 + .../options/BasicOptionObjectFactory.java | 141 + .../vmTestbase/vm/share/options/FClass.java | 49 + .../vmTestbase/vm/share/options/Factory.java | 69 + .../IgnoreUnknownArgumentsHandler.java | 30 + .../vm/share/options/ObjectFactory.java | 74 + .../vmTestbase/vm/share/options/Option.java | 69 + .../vm/share/options/OptionDefinition.java | 120 + .../vm/share/options/OptionError.java | 35 + .../vm/share/options/OptionHandler.java | 50 + .../vm/share/options/OptionObjectFactory.java | 74 + .../vm/share/options/OptionSupport.java | 76 + .../vmTestbase/vm/share/options/Options.java | 44 + .../vm/share/options/OptionsMap.java | 38 + .../vm/share/options/OptionsSetup.java | 327 ++ .../vm/share/options/ParserException.java | 42 + .../vm/share/options/PrimitiveParser.java | 297 + .../vm/share/options/package-info.java | 258 + .../test/BasicObjectFactoryUsageExample.java | 57 + .../test/ExampleWithNonprimitiveOptions.java | 67 + .../vm/share/options/test/SimpleExample.java | 62 + .../SimpleExampleWithOptionsAnnotation.java | 79 + .../share/options/test/SubClassExample.java | 66 + .../vm/share/options/test/package-info.java | 30 + .../vm/share/process/CmdExecutor.java | 63 + .../vm/share/process/MessageInput.java | 37 + .../vm/share/process/MessageOutput.java | 29 + .../vm/share/process/ProcessExecutor.java | 296 + .../vm/share/process/ProcessHandler.java | 102 + .../vm/share/process/StreamListener.java | 36 + .../vm/share/process/StreamLogger.java | 55 + .../vm/share/process/StreamMessageInput.java | 187 + .../vm/share/process/StreamMessageOutput.java | 56 + .../vm/share/process/StreamReader.java | 150 + .../vmTestbase/vm/share/stack/StackUtils.java | 132 + .../AbstractClassFileTransformer.java | 44 + .../share/transform/AnnotationAppender.java | 62 + .../transform/TransformingClassLoader.java | 61 + .../vm/share/vmcrasher/Crasher.java | 29 + .../vm/share/vmcrasher/CrasherFactory.java | 35 + .../vm/share/vmcrasher/SignalCrasher.java | 35 + .../vm/share/vmcrasher/UnsafeGCCrasher.java | 51 + .../vm/share/vmcrasher/UnsafeJavaCrasher.java | 47 + .../vmstresser/CompileAndDeoptimize.java | 79 + .../share/vmstresser/MetaspaceStresser.java | 260 + 331 files changed, 58155 insertions(+) create mode 100644 test/hotspot/jtreg/vmTestbase/ExecDriver.java create mode 100644 test/hotspot/jtreg/vmTestbase/PropertyResolvingWrapper.java create mode 100644 test/hotspot/jtreg/vmTestbase/README.md create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/AbstractGoldChecker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/ArgumentParser.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Consts.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/CustomClassLoader.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Debug.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Denotation.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/DummyClassLoader.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Failure.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/FileUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Finalizable.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/FinalizableObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Finalizer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/GoldChecker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Grep.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Harakiri.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Log.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/ObjectInstancesManager.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Oddity.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Pair.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Paragrep.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/PrintProperties.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/README create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObjectSet.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/StringGoldChecker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/TestBug.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/TestFailure.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/TestJNIError.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/TimeoutHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/TreeNodesDenotation.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/Wicket.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODRunnerArgParser.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTargetArgParser.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentInformation.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentsAttacher.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/ProcessExecutor.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/Utils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/classload/ClassPathNonDelegatingClassLoader.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/classload/TemplateClass.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/Algorithms.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllDiag.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllMemoryObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/ArgumentHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/Cell.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/CircularLinkedList.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/ClassChain.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinDiag.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject1.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParams.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParamsAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCTestBase.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/IndexPair.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/LinkedMemoryObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/Matrix.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/MemoryObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/OOMStress.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/ThreadedGCTest.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/TwoFieldsObject.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/classes/Classes.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedStrategyProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer1Aware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducerAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategy.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategyAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/RandomProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayOfProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/BooleanArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ByteArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/CharArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/DoubleArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/FloatArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/IntArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/LongArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ObjectArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ShortArrayProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/classload/GeneratedClassProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/CircularListProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/LinearListProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TraceProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TwoFieldsObjectProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/AllMemoryObjectProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObject1Producer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObjectProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/MemoryObjectProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/InternedStringProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/RandomStringProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/SimpleStringProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/tree/NonbranchyTreeProducer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionObjectLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionTimedLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Locker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockerUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Lockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockersAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/MultiLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/JNILockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLockers.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/Tree.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/TreeNode.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/AbstractJDIDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Binder.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ConnectorTest.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggeeEventData.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggerEventData.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventTestTemplates.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ForceEarlyReturnDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MockReferenceType.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEnterExecutor.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEventsDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugConnectors.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugTransportService.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass1.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass2.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType2.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestInterfaceImplementer1.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ThreadState.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ValueConversionDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/InstallSDE.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebuggee.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebugger.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapGenerator.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapStratum.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/TestClass1.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jni/JNIreferences.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jni/README create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ConversionUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeArgumentHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeBinder.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeProcess.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ForceEarlyReturnTestThread.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/IOPipe.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/jpda/StateTestThread.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockMaker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockedThread.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockType.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/MonitorLockingThread.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/ReentrantLockLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedBlockLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedMethodLocker.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/log/Log.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/log/LogAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/log/LogSupport.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/README create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.c create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.h create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/FinRunner.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/GCRunner.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/MemDiag.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunner.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunnerAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParams.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParamsAware.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersBTree.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersChain.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/Dumpable.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/ExecutionController.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/Initializable.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyFormatString.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyIntArrayToString.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyObjectArrayToString.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/LocalRandom.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/StressOptions.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/Test.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/TestBase.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/TestExitCode.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/TestUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/Tests.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutWatchdog.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/CommentedFileReader.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/FileUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.c create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/RandomEx.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/StringUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/UnsafeAccess.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/VMRuntimeEnvUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingHeap.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingHelper.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingWithWhiteBox.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/libProcessUtils.c create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/monitoring/MemoryPoolFinder.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryManagerData.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryPoolData.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryUsageData.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/BasicObjectFactory.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/BasicOptionObjectFactory.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/FClass.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/Factory.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/IgnoreUnknownArgumentsHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/ObjectFactory.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/Option.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionDefinition.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionError.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionObjectFactory.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionSupport.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/Options.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsMap.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsSetup.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/ParserException.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/PrimitiveParser.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/package-info.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/test/BasicObjectFactoryUsageExample.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/test/ExampleWithNonprimitiveOptions.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExample.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExampleWithOptionsAnnotation.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/test/SubClassExample.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/options/test/package-info.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/CmdExecutor.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/MessageInput.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/MessageOutput.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessExecutor.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessHandler.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/StreamListener.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/StreamLogger.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageInput.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageOutput.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/process/StreamReader.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/stack/StackUtils.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/transform/AbstractClassFileTransformer.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/transform/AnnotationAppender.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/transform/TransformingClassLoader.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/Crasher.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/CrasherFactory.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/SignalCrasher.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeGCCrasher.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeJavaCrasher.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/CompileAndDeoptimize.java create mode 100644 test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/MetaspaceStresser.java diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk index 1e5fc8b4a49..9b32fc2935d 100644 --- a/make/test/JtregNativeHotspot.gmk +++ b/make/test/JtregNativeHotspot.gmk @@ -48,6 +48,21 @@ BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(OUTPUTDIR)/support/test/hotspot/jtreg/native BUILD_HOTSPOT_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/hotspot/jtreg +################################################################################ +# Former VM TestBase tests. +################################################################################ + +VM_TESTBASE_DIR := $(TOPDIR)/test/hotspot/jtreg/vmTestbase + +VM_SHARE_INCLUDES := \ + -I$(VM_TESTBASE_DIR)/vm/share \ + -I$(VM_TESTBASE_DIR)/nsk/share/native \ + -I$(VM_TESTBASE_DIR)/nsk/share/jni + +BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES) + +################################################################################ + # Platform specific setup ifneq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc) BUILD_HOTSPOT_JTREG_EXCLUDE += liboverflow.c exeThreadSignalMask.c diff --git a/test/hotspot/jtreg/vmTestbase/ExecDriver.java b/test/hotspot/jtreg/vmTestbase/ExecDriver.java new file mode 100644 index 00000000000..46da6be51b6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/ExecDriver.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +/** + * Starts a new process to execute a command. + *

Usage: --java|--cmd|--launcher + + *

If {@code --cmd} flag is specified, the arguments are treated as + * a program to run and its arguments. Non-zero exit code of the created process + * will be reported as an {@link AssertionError}. + *

If {@code --java} flag is specified, the arguments are passed to {@code java} + * from JDK under test. If exit code doesn't equal to 0 or 95, {@link AssertionError} + * will be thrown. + *

If {@code --launcher} flag is specified, the arguments treated similar as + * for {@code --cmd}, but the started process will have the directory which + * contains {@code jvm.so} in dynamic library path, and {@code test.class.path} + * as CLASSPATH environment variable. Exit codes are checked as in + * {@code --java}, i.e. 0 or 95 means pass. + */ +public class ExecDriver { + public static void main(String[] args) throws IOException, InterruptedException { + boolean java = false; + boolean launcher = false; + + String type = args[0]; + switch (type) { + case "--java": + String[] oldArgs = args; + int count; + String libraryPath = System.getProperty("test.nativepath"); + if (libraryPath != null && !libraryPath.isEmpty()) { + count = 4; + args = new String[args.length + 3]; + args[3] = "-Djava.library.path=" + libraryPath; + } else { + count = 3; + args = new String[args.length + 2]; + } + args[0] = javaBin(); + args[1] = "-cp"; + args[2] = Utils.TEST_CLASS_PATH; + System.arraycopy(oldArgs, 1, args, count, oldArgs.length - 1); + java = true; + break; + case "--launcher": + java = true; + launcher = true; + case "--cmd": + args = Arrays.copyOfRange(args, 1, args.length); + break; + default: + throw new Error("unknown type: " + type); + } + // adding 'test.vm.opts' and 'test.java.opts' + if (java) { + String[] oldArgs = args; + String[] testJavaOpts = Utils.getTestJavaOpts(); + if (testJavaOpts.length > 0) { + args = new String[args.length + testJavaOpts.length]; + // bin/java goes before options + args[0] = oldArgs[0]; + // then external java options + System.arraycopy(testJavaOpts, 0, args, 1, testJavaOpts.length); + // and then options and args from a test + System.arraycopy(oldArgs, 1, args, 1 + testJavaOpts.length, oldArgs.length - 1); + } + } + String command = Arrays.toString(args); + System.out.println("exec " + command); + + ProcessBuilder pb = new ProcessBuilder(args); + // adding jvm.so to library path + if (launcher) { + Path dir = Paths.get(Utils.TEST_JDK); + String name; + if (Platform.isWindows()) { + dir = dir.resolve("bin") + .resolve(variant()) + .toAbsolutePath(); + name = "PATH"; + } else { + dir = dir.resolve("lib") + .resolve(variant()) + .toAbsolutePath(); + name = Platform.isOSX() ? "DYLD_LIBRARY_PATH" : "LD_LIBRARY_PATH"; + } + + System.out.println(" with " + name + " = " + + pb.environment() + .merge(name, dir.toString(), (x, y) -> y + File.pathSeparator + x)); + System.out.println(" with CLASSPATH = " + + pb.environment() + .put("CLASSPATH", Utils.TEST_CLASS_PATH)); + } + Process p = pb.start(); + // inheritIO does not work as expected for @run driver + new Thread(() -> copy(p.getInputStream(), System.out)).start(); + new Thread(() -> copy(p.getErrorStream(), System.out)).start(); + int exitCode = p.waitFor(); + + if (exitCode != 0 && (!java || exitCode != 95)) { + throw new AssertionError(command + " exit code is " + exitCode); + } + } + + private static String variant() { + if (Platform.isServer()) { + return "server"; + } else if (Platform.isClient()) { + return "client"; + } else if (Platform.isMinimal()) { + return "minimal"; + } else { + throw new Error("TESTBUG: unsuppported vm variant"); + } + } + + + private static void copy(InputStream is, OutputStream os) { + byte[] buffer = new byte[1024]; + int n; + try (InputStream close = is) { + while ((n = is.read(buffer)) != -1) { + os.write(buffer, 0, n); + } + os.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static String javaBin() { + return Paths.get(Utils.TEST_JDK) + .resolve("bin") + .resolve("java") + .toAbsolutePath() + .toString(); + } +} + diff --git a/test/hotspot/jtreg/vmTestbase/PropertyResolvingWrapper.java b/test/hotspot/jtreg/vmTestbase/PropertyResolvingWrapper.java new file mode 100644 index 00000000000..52ed1c1122b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/PropertyResolvingWrapper.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +/** + * Replaces all {@code ${}} with value of corresponding property({@code X}), + * resulting string is handled similarly to {@code @run main} in jtreg. + * In other words, {@code main} of first token will be executed with the rest + * tokens as arguments. + * + * If one of properties can't be resolved, {@link Error} will be thrown. + */ +public class PropertyResolvingWrapper { + private static final Properties properties; + static { + Properties p = System.getProperties(); + String name = p.getProperty("os.name"); + String arch = p.getProperty("os.arch"); + String family; + String simple_arch; + + // copy from jtreg/src/share/classes/com/sun/javatest/regtest/config/OS.java + if (name.startsWith("AIX")) + family = "aix"; + else if (name.startsWith("Linux")) + family = "linux"; + else if (name.startsWith("Mac") || name.startsWith("Darwin")) + family = "mac"; + else if (name.startsWith("OS400") || name.startsWith("OS/400") ) + family = "os400"; + else if (name.startsWith("SunOS") || name.startsWith("Solaris")) + family = "solaris"; + else if (name.startsWith("Windows")) + family = "windows"; + else + family = name.replaceFirst("^([^ ]+).*", "$1"); // use first word of name + + if (arch.contains("64") + && !arch.equals("ia64") + && !arch.equals("ppc64") + && !arch.equals("ppc64le") + && !arch.equals("zArch_64") + && !arch.equals("aarch64")) + simple_arch = "x64"; + else if (arch.contains("86")) + simple_arch = "i586"; + else if (arch.equals("ppc") || arch.equals("powerpc")) + simple_arch = "ppc"; + else if (arch.equals("s390x") || arch.equals("zArch_64")) + simple_arch = "s390x"; + else + simple_arch = arch; + + p.setProperty("os.family", family); + p.setProperty("os.simpleArch", simple_arch); + properties = p; + } + + public static void main(String[] args) throws Throwable { + List command = new ArrayList<>(args.length); + for (int i = 0; i < args.length; ++i) { + StringBuilder arg = new StringBuilder(args[i]); + while (i < args.length - 1 + && (arg.chars() + .filter(c -> c == '"') + .count() % 2) != 0) { + arg.append(" ") + .append(args[++i]); + } + command.add(eval(arg.toString())); + } + System.out.println("run " + command); + try { + Class.forName(command.remove(0)) + .getMethod("main", String[].class) + .invoke(null, new Object[]{command.toArray(new String[0])}); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + t = t != null ? t : e; + throw t; + } + } + + private static String eval(String string) { + int index; + int current = 0; + StringBuilder result = new StringBuilder(); + while (current < string.length() && (index = string.indexOf("${", current)) >= 0) { + result.append(string.substring(current, index)); + int endName = string.indexOf('}', index); + current = endName + 1; + String name = string.substring(index + 2, endName); + String value = properties.getProperty(name); + if (value == null) { + throw new Error("can't find property " + name); + } + result.append(value); + } + if (current < string.length()) { + result.append(string.substring(current)); + } + int length = result.length(); + + if (length > 1 && result.charAt(0) == '"' && result.charAt(length - 1) == '"') { + result.deleteCharAt(length - 1); + result.deleteCharAt(0); + } + return result.toString(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/README.md b/test/hotspot/jtreg/vmTestbase/README.md new file mode 100644 index 00000000000..86f51382138 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/README.md @@ -0,0 +1,10 @@ +# VM Testbase landing + +This directory serves as a _temporary_ landing place for tests converted from so-called VM testbase. +Most of these tests have been written a long time ago, don't meet modern coding +standards, guidelines and are in need of reworking. +Eventually, all the tests located here should be reworked and moved accordingly to +regular JTReg test suite directory layout convention, i.e. following the same +layout as product code as close as possible. + +New tests must **not** be added into this directory. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/AbstractGoldChecker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/AbstractGoldChecker.java new file mode 100644 index 00000000000..a348346fe91 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/AbstractGoldChecker.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; +import java.io.UnsupportedEncodingException; + +public abstract class AbstractGoldChecker { + + private final StringBuffer sb = new StringBuffer(); + + protected abstract String getGoldenString(); + + public void print(boolean b) { + sb.append(String.valueOf(b)); + } + + public void print(byte b) { + sb.append(String.valueOf(b)); + } + + public void print(char c) { + sb.append(String.valueOf(c)); + } + + public void print(int i) { + sb.append(String.valueOf(i)); + } + + public void print(long l) { + sb.append(String.valueOf(l)); + } + + public void print(float f) { + sb.append(String.valueOf(f)); + } + + public void print(double d) { + sb.append(String.valueOf(d)); + } + + public void print(String s) { + sb.append(s); + } + + public void println() { + sb.append('\n'); + } + + public void println(boolean b) { + sb.append(String.valueOf(b)); + sb.append('\n'); + } + + public void println(byte b) { + sb.append(String.valueOf(b)); + sb.append('\n'); + } + + public void println(char c) { + sb.append(String.valueOf(c)); + sb.append('\n'); + } + + public void println(int i) { + sb.append(String.valueOf(i)); + sb.append('\n'); + } + + public void println(long l) { + sb.append(String.valueOf(l)); + sb.append('\n'); + } + + public void println(float f) { + sb.append(String.valueOf(f)); + sb.append('\n'); + } + + public void println(double d) { + sb.append(String.valueOf(d)); + sb.append('\n'); + } + + public void println(String s) { + sb.append(s); + sb.append('\n'); + } + + public void check() { + String testOutput; + try { + testOutput = new String(sb.toString().getBytes("US-ASCII"), "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new TestFailure(e); + } + + String goldOutput = getGoldenString(); + if (!compare(testOutput, goldOutput)) { + throw new TestFailure( + "Gold comparison failed\n" + + "\n" + + "Test output:\n" + + "============\n" + + "\n" + + testOutput + + "\n" + + "------------\n" + + "\n" + + "Gold output:\n" + + "============\n" + + "\n" + + goldOutput + + "\n" + + "------------\n" + + "\n" + ); + } + } + + public boolean compare(String src, String dst) { + int i1 = 0; + int i2 = 0; + + int src_len = src.length(); + int dst_len = dst.length(); + + while ((i1 < src_len) && (i2 < dst_len)) { + + char c1 = src.charAt(i1++); + if ((c1 == '\r') && (i1 < src_len)) { + c1 = src.charAt(i1++); + } + + char c2 = dst.charAt(i2++); + if ((c2 == '\r') && (i2 < dst_len)) { + c2 = dst.charAt(i2++); + } + + if (c1 != c2) { + return false; + } + } + return (i1 == src_len) && (i2 == dst_len); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ArgumentParser.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ArgumentParser.java new file mode 100644 index 00000000000..fe63159577d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ArgumentParser.java @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.*; + +import nsk.share.test.StressOptions; +import nsk.share.test.Stresser; + +/** + * Parser for JDI test's command-line arguments. + *

+ * Test's command line may contain two kind of arguments, namely: + *

    + *
  • options for ArgumentParser + *
  • other arguments for the test itself + *
+ *

+ * We call raw arguments the args[] array + * passed to the test's method main(String args[]). + * ArgumentParser instance initialized with raw arguments serves to parse + * these two kinds of arguments. Use ArgumentParser(args[]) + * constructor, or setRawArguments(args[]) method + * to initialize a ArgumentParser instance with particular raw arguments. + *

+ * Arguments, started with ``-'' symbol are called options. + * They are recognized by ArgumentParser and are used by support classes + * (such as Log, Binder, etc.). + * These options should be specified in the following general form: + *

    + *
  • -option=value + *
+ * or + *
    + *
  • -option value + *
+ * List of the recognized options with their values may be obtained by + * invoking method getOptions() that returnes + * a Properties object with options values. + * It is not recommended to get options value directly. An appropriate methods + * such as verbose(), getArch(), etc. should be used + * instead. + * Options may appear in the test command line in any order. + *

+ * All the other arguments of command line are called test arguments + * (or simply arguments). These arguments should be handled by test itself. + * Full list of the test arguments in the same order as they appears in the command line + * may be obtained by invoking method getArguments(). + *

+ * Following is the list of basic options accepted by AgrumentParser: + *

    + *
  • -arch=<${ARCH}> - + * architecture name + *
  • -waittime=<minutes> - + * timeout in minutes for waiting events or so + *
  • -verbose - + * verbose Log mode (default is quiet) + *
  • -trace.time - + * prefix log messages with timestamps (default is no) + *
+ * Also AgrumentParser supports following stress options (see nsk.share.test.StressOptions for details): + *
    + *
  • -stressTime + *
  • -stressIterationsFactor + *
  • -stressThreadsFactor + *
  • -stressDebug + *
+ *

+ * Note, that the tests from the particular subsuites have its own argument handlers + * wich accepts additional options. See jpda.DebugeeArgumentHandler, + * jdi.ArgumentHandler, jdwp.ArgumentHandler. + * + * @see #setRawArguments(String[]) + * @see #getRawArguments() + * @see #getArguments() + * @see #getOptions() + * + * @see nsk.share.jpda.DebugeeArgumentHandler + * @see nsk.share.jdwp.ArgumentHandler + * @see nsk.share.jdi.ArgumentHandler + * @see nsk.share.jvmti.ArgumentHandler + * @see nsk.share.monitoring.ArgumentHandler + */ +public class ArgumentParser { + + /** + * Raw array of command-line arguments. + * + * @see #setRawArguments(String[]) + * @see #getRawArguments() + */ + protected String rawArguments[] = null; + + /** + * Refined arguments -- raw arguments but options. + * + * @see #options + * @see #getArguments() + */ + protected String arguments[] = null; + + /** + * Recognized options for ArgumentParser class. + * + * @see #arguments + * @see #getOptions() + */ + protected Properties options = new Properties(); + + /** + * Make new ArgumentParser object with default values of otions. + * This constructor is used only to obtain default values of options. + * + * @see #setRawArguments(String[]) + */ + protected ArgumentParser() { + String[] args = new String[0]; + setRawArguments(args); + } + + /** + * Keep a copy of raw command-line arguments and parse them; + * but throw an exception on parsing error. + * + * @param args Array of the raw command-line arguments. + * + * @throws BadOption If option values are invalid. + * + * @see #setRawArguments(String[]) + * @see BadOption + */ + public ArgumentParser(String args[]) { + setRawArguments(args); + } + + /** + * Return a copy of the raw command-line arguments kept by + * this ArgumentParser instance. + * + * @throws NullPointerException If raw arguments were not + * set for this instance. + * + * @see #setRawArguments(String[]) + */ + public String[] getRawArguments() { + return (String[]) rawArguments.clone(); + } + + /** + * Return given raw command-line argument. + * + * @param index index of argument + * @return value of raw argument + */ + public String getRawArgument(int index) { + return rawArguments[index]; + } + + /** + * Return refined array of test arguments (only those of the raw + * arguments which are not recognized as options for ArgumentParser). + * + *

Note, that sintax of test arguments was not checked; + * while syntax of arguments describing ArgumentParser's options + * was checked while raw arguments were set to this ArgumentParser + * instance. + * + * @throws NullPointerException If raw arguments were not + * set for this instance. + * + * @see #setRawArguments(String[]) + * @see #getOptions() + */ + public String[] getArguments() { + return (String[]) arguments.clone(); + } + + /** + * Return list of recognized otions with their values in the form of + * Properties object. + * If no options has been recognized, this list will be empty. + * + * @see #setRawArguments(String[]) + * @see #getArguments() + */ + public Properties getOptions() { + return (Properties) options.clone(); + } + + /** + * Join specified arguments into one line using given quoting + * and separator symbols. + * + * @param args Array of the command-line arguments + * @param quote Symbol used to quote each argument + * @param separator Symbol used as separator between argumnets + * @return Single line with arguments + */ + static public String joinArguments(String args[], String quote, String separator) { + if (args.length <= 0) { + return ""; + } + String line = quote + args[0] + quote; + for (int i = 1; i < args.length; i++) { + line += separator + quote + args[i] + quote; + } + return line; + } + + /** + * Join specified arguments into one line using given quoting symbol + * and space as a separator symbol. + * + * @param args Array of the command-line arguments + * @param quote Symbol used to quote each argument + * @return Single line with arguments + */ + static public String joinArguments(String args[], String quote) { + return joinArguments(args, quote, " "); + } + + /** + * Keep a copy of command-line arguments and parse them; + * but throw an exception on parsing error. + * + * @param args Array of the raw command-line arguments. + * + * @throws BadOption If an option has invalid value. + * + * @see #getRawArguments() + * @see #getArguments() + */ + public void setRawArguments(String args[]) { + this.rawArguments = (String[]) args.clone(); + parseArguments(); + } + + /** + * Add or replace given option value in options list and in raw arguments list. + * Use specified rawPrefix while adding to raw arguments list. + * + * @see #getRawArguments() + * @see #getOptions() + */ + public void setOption(String rawPrefix, String name, String value) { + String prefix = rawPrefix + name + "="; + String arg = prefix + value; + + options.setProperty(name, value); + + int length = rawArguments.length; + boolean found = false; + for (int i = 0; i < length; i++) { + if (rawArguments[i].startsWith(prefix)) { + found = true; + rawArguments[i] = arg; + break; + } + } + + if (!found) { + String[] newRawArguments = new String[length + 1]; + for (int i = 0; i < length; i++) { + newRawArguments[i] = rawArguments[i]; + } + newRawArguments[length] = arg; + rawArguments = newRawArguments; + } + } + + /** + * Return current architecture name from ArgumentParser's + * options. + * + *

Note that null string is returning if test argument + * -arch has not been set. + * + * @see #setRawArguments(String[]) + */ + public String getArch() { + return options.getProperty("arch"); + } + + /** + * Timeout (in minutes) for test's critical section like: + * (a) awaiting for an event, or conversly (b) making sure + * that there is no unexpected event. + * + *

By default, 2 minutes is returned if option + * -waittime is not set with command line. + * + * @see TimeoutHandler + */ + public int getWaitTime() { + String val = options.getProperty("waittime", "2"); + int minutes; + try { + minutes = Integer.parseInt(val); + } catch (NumberFormatException e) { + throw new TestBug("Not integer value of \"waittime\" argument: " + val); + } + return minutes; + } + + /** + * Return boolean value of current Log mode: + *

    + *
  • true if Log mode is verbose. + *
  • false otherwise. + * + *

    Note that default Log mode is quiet if test argument + * -verbose has not been set. + * + * @see #setRawArguments(String[]) + */ + public boolean verbose() { + return options.getProperty("verbose") != null; + } + + /** + * Return boolean value of setting of timestamp for log messages: + *

      + *
    • true if Log messages are timestamp'ed. + *
    • false otherwise. + * + *

      Note that by default Log messages won't be timestamp'ed until + * -trace.time has not been set. + * + * @see #setRawArguments(String[]) + */ + public boolean isTimestamp() { + return options.getProperty("trace.time") != null; + } + + /** + * Return level of printing tracing mesages for debugging purpose. + * Level 0 means no tracing messages at all. + * + *

      Note that by default no tracing messages will be printed out + * until -trace.level has not been set. + * + * @see #setRawArguments(String[]) + */ + public int getTraceLevel() { + String value = options.getProperty("trace.level", Integer.toString(Log.TraceLevel.DEFAULT)); + try { + int level = Integer.parseInt(value); + return level; + } catch (NumberFormatException e) { + throw new Failure("Not integer value of -trace.level option: " + value); + } + } + + /** + * Parse arguments from rawArgumnets, extact recognized options, + * check legality of options values options and store non-option + * arguments. + * + * @throws NullPointerException If raw arguments were not set + * for this ArgumentParser instance. + * @throws BadOption If Option name is not accepted or + * option has illegal value. + * + * @see #setRawArguments(String[]) + * @see #checkOption(String, String) + * @see #checkOptions() + */ + protected void parseArguments() { + String selected[] = new String [rawArguments.length]; + Properties properties = new Properties(); + int count = 0; + for (int i=0; i + * Derived classes for hadling test arguments in particular sub-suites + * override this method to allow to accept sub-suite specific options. + * However, they should invoke this method of the base class to enshure + * that the basic options will be accepted too. + * + * @return true if option is allowed and has legel value + * false if option is unknown + * + * @throws BadOption If value of the allowed option is illegal. + * + * @see #setRawArguments(String[]) + * @see #parseArguments() + */ + protected boolean checkOption(String option, String value) { + + // accept arguments of nsk.share.test.StressOptions + if (StressOptions.isValidStressOption(option)) + return true; + + // options with any string value + if (option.equals("arch")) { + return true; + } + + // options with positive integer value + if (option.equals("waittime") + || option.equals("trace.level")) { + try { + int number = Integer.parseInt(value); + if (number < 0) { + throw new BadOption(option + ": value must be a positive integer"); + } + } catch (NumberFormatException e) { + throw new BadOption(option + ": value must be an integer"); + } + return true; + } + + // options without any value + if (option.equals("verbose") + || option.equals("vbs") + || option.equals("trace.time")) { + if (!(value == null || value.length() <= 0)) { + throw new BadOption(option + ": no value must be specified"); + } + return true; + } + + return false; + } + + /** + * Check that the value of all options are not inconsistent. + * This method is invoked by parseArguments() + * + * @throws BadOption If value of the options are inconsistent + * + * @see #parseArguments() + */ + protected void checkOptions() { + // do nothing + } + + /** + * Thrown if invalid option or option value is found. + */ + public static class BadOption extends IllegalArgumentException { + /** + * Explain the reason. + * + * @param message Printing message. + */ + public BadOption(String message) { + super(message); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java new file mode 100644 index 00000000000..3024ae1d7a5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.File; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.nio.file.Files; +import java.util.Arrays; + +public class ClassFileFinder { + private ClassFileFinder() { } + /** + * Searches for a classfile for the specified class in the specified + * classpath. + * + * @param name a classname + * @param classPath @{link File.pathSeparator} separated directories + * @return an absolute path to the found classfile, or null if it cannot be + * found + */ + public static Path findClassFile(String name, String classPath) { + return Arrays.stream(classPath.split(File.pathSeparator)) + .map(java.nio.file.Paths::get) + .map(p -> p.resolve(name.replace('.', File.separatorChar) + ".class")) + .filter(p -> java.nio.file.Files.exists(p)) + .map(Path::toAbsolutePath) + .findAny() + .orElse(null); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java new file mode 100644 index 00000000000..03e0362f9ef --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Warning! Using this component need VM option -XX:-UseGCOverheadLimit + * + */ + +package nsk.share; + +import java.util.*; +import nsk.share.gc.gp.*; +import nsk.share.test.ExecutionController; +import nsk.share.test.Stresser; + +/** + * The ClassUnloader class allows to force VM to unload class(es) + * using memory stressing technique. + * + *

      The method unloadClass() is provided which eats memory + * to enforce GC to cleanup the heap. So, if all references to a class + * and its loader are canceled, this may result in unloading the class. + * + *

      ClassUnloader mainly intends to unload a class which was loaded + * with especial ClassUnloader.loadClass() method. + * A class is considered unloaded if its class loader is finalized. + * If there no finalization of class loader detected for some timeout, + * class is considered still loaded and method returns false. + * + *

      Such finalization control applies only to a class loaded by + * ClassUnloader's loadClass() method. Otherwise, if there + * was no such class loaded, unloadClass() doesn't wait + * for a timeout and always returns false. + * + *

      By default internal class loader of CustomClassLoader class + * is used for loading classes. This class loader can load class from .class file + * located in the specified directory. + * Application may define its own class loader, which may load classes using + * any other technique. Such class loader should be derived from base + * CustomClassLoader class, and set by setClassLoader() + * method. + * + * @see #setClassLoader(CustomClassLoader) + * @see #loadClass(String) + * @see #loadClass(String, String) + * @see #unloadClass() + */ +public class ClassUnloader { + + /** + * Class name of default class loader. + */ + public static final String INTERNAL_CLASS_LOADER_NAME = "nsk.share.CustomClassLoader"; + + /** + * Whole amount of time in milliseconds to wait for class loader finalization. + */ + private static final int WAIT_TIMEOUT = 15000; + + /** + * Piece of time in milliseconds to wait in a loop for class loader finalization. + */ + private static final int WAIT_DELTA = 1000; + + /** + * Has class loader been finalized or not. + */ + volatile boolean finalized = false; + + /** + * Current class loader used for loading classes. + */ + private CustomClassLoader customClassLoader = null; + + /** + * List of classes loaded with current class loader. + */ + private Vector> classObjects = new Vector>(); + + /** + * Class object of the first class been loaded with current class loader. + * To get the rest loaded classes use getLoadedClass(int). + * The call getLoadedClass() is effectively equivalent to the call + * getLoadedClass(0) + * + * @return class object of the first loaded class. + * + * @see #getLoadedClass(int) + */ + public Class getLoadedClass() { + return classObjects.get(0); + } + + /** + * Returns class objects at the specified index in the list of classes loaded + * with current class loader. + * + * @return class objects at the specified index. + */ + public Class getLoadedClass(int index) { + return classObjects.get(index); + } + + /** + * Creates new instance of CustomClassLoader class as the current + * class loader and clears the list of loaded classes. + * + * @return created instance of CustomClassLoader class. + * + * @see #getClassLoader() + * @see #setClassLoader(CustomClassLoader) + */ + public CustomClassLoader createClassLoader() { + customClassLoader = new CustomClassLoader(this); + classObjects.removeAllElements(); + + return customClassLoader; + } + + /** + * Sets new current class loader and clears the list of loaded classes. + * + * @see #getClassLoader() + * @see #createClassLoader() + */ + public void setClassLoader(CustomClassLoader customClassLoader) { + this.customClassLoader = customClassLoader; + classObjects.removeAllElements(); + customClassLoader.setClassUnloader(this); + } + + /** + * Returns current class loader or null if not yet created or set. + * + * @return class loader object or null. + * + * @see #createClassLoader() + * @see #setClassLoader(CustomClassLoader) + */ + public CustomClassLoader getClassLoader() { + return customClassLoader; + } + + /** + * Loads class for specified class name using current class loader. + * + *

      Current class loader should be set and capable to load class using only + * given class name. No other information such a location of .class files + * is passed to class loader. + * + * @param className name of class to load + * + * @throws ClassNotFoundException if no bytecode found for specified class name + * @throws Failure if current class loader is not specified; + * or if class was actually loaded with different class loader + * + * @see #loadClass(String, String) + */ + public void loadClass(String className) throws ClassNotFoundException { + + if (customClassLoader == null) { + throw new Failure("No current class loader defined"); + } + + Class cls = Class.forName(className, true, customClassLoader); + + // ensure that class was loaded by current class loader + if (cls.getClassLoader() != customClassLoader) { + throw new Failure("Class was loaded by unexpected class loader: " + cls.getClassLoader()); + } + + classObjects.add(cls); + } + + /** + * Loads class from .class file located into specified directory using + * current class loader. + * + *

      If there is no current class loader, then default class loader + * is created using createClassLoader(). Parameter classDir + * is passed to class loader using CustomClassLoader.setClassPath() + * method before loading class. + * + * @param className name of class to load + * @param classDir path to .class file location + * + * @throws ClassNotFoundException if no .class file found + * for specified class name + * @throws Failure if class was actually loaded with different class loader + * + * @see #loadClass(String) + * @see CustomClassLoader#setClassPath(String) + */ + public void loadClass(String className, String classDir) throws ClassNotFoundException { + + if (customClassLoader == null) { + createClassLoader(); + } + + customClassLoader.setClassPath(classDir); + loadClass(className); + } + + /** + * Forces GC to unload previously loaded classes by cleaning all references + * to class loader with its loaded classes and eating memory. + * + * @return true if classes unloading has been detected + or false otherwise + * + * @throws Failure if exception other than OutOfMemoryError + * is thrown while eating memory + * + * @see #eatMemory() + */ + public boolean unloadClass(ExecutionController stresser) { + + finalized = false; + + // free references to class and class loader to be able for collecting by GC + long waitTimeout = (customClassLoader == null) ? 0 : WAIT_TIMEOUT; + classObjects.removeAllElements(); + customClassLoader = null; + + // force class unloading by eating memory pool + eatMemory(stresser); + + // give GC chance to run and wait for finalization + long timeToFinish = System.currentTimeMillis() + waitTimeout; + while (!finalized && System.currentTimeMillis() < timeToFinish) { + if (!stresser.continueExecution()) { + return false; + } + try { + // suspend thread for a while + Thread.sleep(WAIT_DELTA); + } catch (InterruptedException e) { + throw new Failure("Unexpected InterruptedException while class unloading: " + e); + } + } + + // force GC to unload marked class loader and its classes + if (finalized) { + Runtime.getRuntime().gc(); + return true; + } + + // class loader has not been finalized + return false; + } + + public boolean unloadClass() { + Stresser stresser = new Stresser() { + + @Override + public boolean continueExecution() { + return true; + } + + }; + return unloadClass(stresser); + } + + /** + * Stresses memory by allocating arrays of bytes. + * + * Note that this method can throw Failure if any exception + * is thrown while eating memory. To avoid OOM while allocating + * exception we preallocate it before the lunch starts. It means + * that exception stack trace does not correspond to the place + * where exception is thrown, but points at start of the method. + * + * @throws Failure if exception other than OutOfMemoryError + * is thrown while eating memory + */ + public static void eatMemory(ExecutionController stresser) { + GarbageUtils.eatMemory(stresser, 50, 1024, 2); + + /* + * System.runFinalization() may potentially fail with OOM. This is why + * System.runFinalization() is repeated several times. + */ + for (int i = 0; i < 10; ++i) { + try { + if(!stresser.continueExecution()) { + return; + } + System.runFinalization(); + break; + } catch (OutOfMemoryError e) { + } + } + } + + /** + * Stresses memory by allocating arrays of bytes. + * + * Note that this method can throw Failure if any exception + * is thrown while eating memory. To avoid OOM while allocating + * exception we preallocate it before the lunch starts. It means + * that exception stack trace does not correspond to the place + * where exception is thrown, but points at start of the method. + * + * @throws Failure if exception other than OutOfMemoryError + * is thrown while eating memory + */ + public static void eatMemory() { + Stresser stresser = new Stresser() { + + @Override + public boolean continueExecution() { + return true; + } + + }; + GarbageUtils.eatMemory(stresser, 50, 1024, 2); + /* + * System.runFinalization() may potentially fail with OOM. This is why + * System.runFinalization() is repeated several times. + */ + for (int i = 0; i < 10; ++i) { + try { + if(!stresser.continueExecution()) { + return; + } + System.runFinalization(); + break; + } catch (OutOfMemoryError e) { + } + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Consts.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Consts.java new file mode 100644 index 00000000000..0f99295d2c5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Consts.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * This class defines constants + * + */ +public class Consts { + + /** + * Exit code when test passed + */ + public final static int TEST_PASSED = 0; + + /** + * Exit code when test failed + */ + public final static int TEST_FAILED = 2; + + /** + * Shift of exit code + */ + public final static int JCK_STATUS_BASE = 95; + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/CustomClassLoader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/CustomClassLoader.java new file mode 100644 index 00000000000..6a42576baa3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/CustomClassLoader.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.*; + +/** + * The CustomClassLoader class is used in ClassUnloader. + * + *

      This class loader can load classes and notify ClassUnloader + * about own finalization to make sure that all loaded classes have been unloaded. + * + *

      By default this class loader loads class from .class file located in directory + * specified with setClassPath() method. To use any other technique + * of class loading one should implement derived class, which would override + * findClass method. + * + * @see nsk.share.ClassUnloader + * + * @see #setClassPath(String) + * @see #findClass(String) + */ +public class CustomClassLoader extends ClassLoader { + + private ClassUnloader classUnloader; + protected String classPath; + + /** + * Initializes a newly created CustomClassloader object + * not yet linked with any ClassUnloader object. + * + */ + public CustomClassLoader() { + super(CustomClassLoader.class.getClassLoader()); + this.classUnloader = null; + } + + /** + * Initializes a newly created CustomClassloader object + * linked with specified ClassUnloader object. + * + * @param classUnloader an instance of ClassUnloader + */ + public CustomClassLoader(ClassUnloader classUnloader) { + super(CustomClassLoader.class.getClassLoader()); + this.classUnloader = classUnloader; + } + + /** + * Links this class loader with specified ClassUnloader object. + * + * @param classUnloader an instance of ClassUnloader + */ + public void setClassUnloader(ClassUnloader classUnloader) { + this.classUnloader = classUnloader; + } + + /** + * Specifies path to .class file location. + * + * @param classPath a path to .class file location + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * Finds and loads class for specified class name. + * This method loads class from .class file located in a directory + * previously specified by setClassPath(). + * + * @param name The name of the class. + * + * @throws ClassNotFoundException if no .class file found + * for specified class name + * + * @see #setClassPath(String) + */ + protected synchronized Class findClass(String name) throws ClassNotFoundException { + java.nio.file.Path path = ClassFileFinder.findClassFile(name, classPath); + if (path == null) { + throw new ClassNotFoundException(name); + } + String classFileName = path.toString(); + + FileInputStream in; + try { + in = new FileInputStream(classFileName); + if (in == null) { + throw new ClassNotFoundException(classFileName); + } + } catch (FileNotFoundException e) { + throw new ClassNotFoundException(classFileName, e); + } + + int len; + byte data[]; + try { + len = in.available(); + data = new byte[len]; + for (int total = 0; total < data.length; ) { + total += in.read(data, total, data.length - total); + } + } catch (IOException e) { + throw new ClassNotFoundException(classFileName, e); + } finally { + try { + in.close(); + } catch (IOException e) { + throw new ClassNotFoundException(classFileName, e); + } + } + + return defineClass(name, data, 0, data.length); + } + + /** + * Notifies ClassUnloader about finalization. + */ + protected void finalize() throws Throwable { + + // notify ClassUnloader about finalization + if (classUnloader != null) { + classUnloader.finalized = true; + } + + super.finalize(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Debug.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Debug.java new file mode 100644 index 00000000000..42eff9c796f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Debug.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +public class Debug +{ + // tests assertion to be valid, otherwise FAIL test with message + static public void Assert(boolean condition, String message) + { + if (!condition) + Debug.Fail(message); + } + + // print message and FAIL test + static public void Fail(String message) + { + System.out.println(message); + System.exit(100); + } + + static public void Fail(Throwable e) + { + Fail(e.toString()); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Denotation.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Denotation.java new file mode 100644 index 00000000000..31353046a44 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Denotation.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.*; + +/** + * Denotation implies a pair of algorithms for naming and + * indexing of some objects. + * + *

      No matter what kind of objects, just make sure that: + *

        + *
      • indexFor(nameFor(index)) equals to index + *
      • + *
      • nameFor(indexFor(name)) is equivalent to name + *
      • + *
      + * + *

      The notions of indeces equality and names equivalence + * are formalized by the methods equality() and + * equivalence() correspondingly. + * + *

      For better understanding of Denotation, you may want to + * see the TreeNodesDenotation class as an implementation example. + * + * @see #equality(int[],int[]) + * @see #equivalence(String,String) + * @see TreeNodesDenotation + */ +abstract public class Denotation { + /** + * Check if the name is legal, and return the + * numeric index for that object denoted by the given + * name. + * + * @throws IllegalArgumentException If the name + * is illegal. + */ + abstract public int[] indexFor(String name); + + /** + * Check if the index[] is legal, and return + * a symbolic name for the object denoted by the given + * index[]. + * + * @throws IllegalArgumentException If the index[] + * is illegal. + */ + abstract public String nameFor(int[] index); + + /** + * Re-call to nameFor(int[]) with the 1-element + * array {i} as the index argument. + * + * @see #nameFor(int[]) + */ + public String nameFor(int i) { + return nameFor(new int[] { i }); + } + + /** + * Re-call to nameFor(int[]) with the 2-elements + * array {i0,i1} as the index argument. + * + * @see #nameFor(int[]) + */ + public String nameFor(int i0, int i1) { + return nameFor(new int[] {i0, i1}); + } + + /** + * Re-call to nameFor(int[]) with the 3-elements + * array {i0,i1,i2} as the index argument. + * + * @see #nameFor(int[]) + */ + public String nameFor(int i0, int i1, int i2) { + return nameFor(new int[] {i0, i1, i2}); + } + + /** + * Indeces equality means equality of objects they denote. + * + *

      Indeces index1[] and index2[] are + * equal, if they are equal as int[] arrays. But, + * there is no index equal to null; particularly, + * null is not equal to itself. + * + * @see Arrays#equals(int[],int[]) + */ + public boolean equality(int[] index1, int[] index2) { + if (index1 == null || index2 == null) + return false; + return Arrays.equals(index1,index2); + } + + /** + * Names equivalence means equality of objects they denote. + * + *

      Strings name1 and name2 are equivalent, + * if correspondent indeces are equal. There is no name + * equivalent to null; particularly, null is + * not equivalent to itself. + * + * @see #equality(int[],int[]) + */ + public boolean equivalence(String name1, String name2) { + if (name1 == null || name2 == null) + return false; + return equality(indexFor(name1),indexFor(name2)); + } + + /** + * Dummy constructor. + */ + protected Denotation() { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/DummyClassLoader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/DummyClassLoader.java new file mode 100644 index 00000000000..07970709a52 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/DummyClassLoader.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * This loader's findClass() method is dummy. + */ +public class DummyClassLoader extends ClassLoader { + /** + * Cannot instantiate w/o a parent loader. + */ + protected DummyClassLoader() { + } + + /** + * Delegate everything to the parent loader. + */ + public DummyClassLoader(ClassLoader parent) { + super(parent); + } + + /** + * Do nothing: parent loader must load everything. + * + * @throws ClassNotFoundException In any case. + */ + public Class findClass(String name) throws ClassNotFoundException { + throw new ClassNotFoundException(name); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Failure.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Failure.java new file mode 100644 index 00000000000..a7992100923 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Failure.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.*; + +/** + * Thrown to indicate failure caused by some occasional reason, + * which does not indicate a problem in the JVM being tested. + */ +public class Failure extends RuntimeException { + /** Enwrap another throwable. */ + public Failure(Throwable throwable) { + super(throwable); + } + + /** Explain particular failure. */ + public Failure(String message) { + super(message); + } + + public Failure(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/FileUtils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/FileUtils.java new file mode 100644 index 00000000000..1b79813c3a2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/FileUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.FileInputStream; + +public class FileUtils { + private FileUtils() { + } + + /** + * Read whole file. + * + * @param file file + * @return contents of file as byte array + */ + public static byte[] readFile(File file) throws IOException { + InputStream in = new FileInputStream(file); + long countl = file.length(); + if (countl > Integer.MAX_VALUE) + throw new IOException("File is too huge"); + int count = (int) countl; + byte[] buffer = new byte[count]; + int n = 0; + try { + while (n < count) { + int k = in.read(buffer, n, count - n); + if (k < 0) + throw new IOException("Unexpected EOF"); + n += k; + } + } finally { + in.close(); + } + return buffer; + } + + /** + * Read whole file. + * + * @param name file name + * @return contents of file as byte array + */ + public static byte[] readFile(String name) throws IOException { + return readFile(new File(name)); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizable.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizable.java new file mode 100644 index 00000000000..d8d13d47669 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizable.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * Finalizable interface allows Finalizer to perform finalization of an object. + * Each object that requires finalization at VM shutdown time should implement this + * interface and activate a Finalizer hook. + * + * @see Finalizer + */ +public interface Finalizable { + + /** + * This method will be invoked by Finalizer when virtual mashine + * shuts down. + * + * @throws Throwable if any throwable exception thrown during finalization + */ + public void finalizeAtExit() throws Throwable; + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/FinalizableObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/FinalizableObject.java new file mode 100644 index 00000000000..6a5b6457fb6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/FinalizableObject.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * This class is an simple exalmple of finalizable object, that implements interface + * Finalizable and invokes standard finalize() method + * as finalization. + * + * @see Finalizable + * @see Finalizer + */ +public class FinalizableObject implements Finalizable { + + /** + * This method will be invoked by Finalizer when virtual mashine + * shuts down. + * For FinalizableObject this method just invoke + * finalize(). + * + * @throws Throwable if any throwable exception thrown during finalization + * + * @see Object#finalize() + * @see Finalizer + */ + public void finalizeAtExit() throws Throwable { + finalize(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizer.java new file mode 100644 index 00000000000..1d274c54b2a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizer.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.Stack; + +/** + * Finalizer performs object finalization when virtual mashine shuts down. + * Finalizer is a thread that acts as a VM shutdown hook. + * This thread will be activated as VM shuts down because of + * invocation of exit() or termination. After activation + * Finalizer just calls finalizeAtExit() method of the specified object. + * The finalizable object should implement interface Finalizable. + * + * @see Finalizable + */ +public class Finalizer { + + /** Finalizer thread to register as a VM shutdown hook. */ + private static FinalizerThread finalizerThread = null; + + /** An object to finalize. */ + private Finalizable object; + + /** + * Create finalizer for the specified object. + */ + public Finalizer(Finalizable object) { + this.object = object; + } + + /** + * Register finalizer for finalization at VM shutdown. + */ + public void activate() { + if (finalizerThread == null) { + finalizerThread = new FinalizerThread("FinalizerThread for Finalizable objects"); + finalizerThread.activate(); + } + finalizerThread.add(object); + } + + /** + * Unregister finalizer for finalization at VM shutdown. + */ + public void deactivate() { + if (finalizerThread == null) + return; + finalizerThread.remove(object); + } + + /** + * Static inner thread that is registered as a VM shutdown hook + * and performs finalization of all registered finalizable objects. + */ + private static class FinalizerThread extends Thread { + + /** Stack of objects registered for finalization. */ + private Stack objects = new Stack(); + + /** Make new instance of FinalizerThread with given thread name. */ + public FinalizerThread(String threadName) { + super(threadName); + } + + /** + * Push an object to the stack of registered objects. + */ + public void add(Finalizable object) { + objects.push(object); + } + + /** + * Remove an object from the stack of registered objects. + */ + public void remove(Finalizable object) { + objects.remove(object); + } + + /** + * Register finalizer thread as a VM shutdown hook. + */ + public void activate() { + Runtime.getRuntime().addShutdownHook( this ); + } + + /** + * Unregister finalizer thread as a VM shutdown hook. + */ + public void deactivate() { + Runtime.getRuntime().removeShutdownHook( this ); + } + + /** + * Pop all registered objects from the stack and finalize them. + */ + public void run() { + while (!objects.empty()) { + Finalizable object = (Finalizable)objects.pop(); + try { + object.finalizeAtExit(); + } catch (ThreadDeath e) { + throw e; + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + } + + } // end of FinalizerThread + +} // end of Finalizer diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/GoldChecker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/GoldChecker.java new file mode 100644 index 00000000000..60821011e2f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/GoldChecker.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +import java.io.*; + +public class GoldChecker extends AbstractGoldChecker +{ + private final String goldOutput; + + public GoldChecker(String main_class_name) { + goldOutput = readGoldStr(main_class_name + ".gold"); + } + + @Override + protected String getGoldenString() { + return goldOutput; + } + + private String readGoldStr(String gold_file_name) { + RandomAccessFile f; + + try { + f = new RandomAccessFile(gold_file_name, "r"); + } catch (FileNotFoundException e) { + throw new TestBug("Unable to open golden file '" + gold_file_name + "' for reading"); + } + + byte[] data; + + try { + int len = (int)f.length(); + data = new byte[len]; + f.read(data); + } catch (IOException e) { + throw new TestBug("Error reading from golden file'" + gold_file_name + "'"); + } + + try { + f.close(); + } catch (IOException e) { + } + + try { + return new String(data, "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new TestFailure( e ); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Grep.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Grep.java new file mode 100644 index 00000000000..9febb5df3f9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Grep.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.*; +import java.util.regex.*; + +/** + * Emulator of perl's grep function. + * This class uses java.util.regexp classes which appear in + * JDK1.4 API. This implies the restriction for this class + * to not be used with the tests against JDKs prior to 1.4. + * + * @see java.util.regex.Pattern + * @see java.util.regex.Matcher + */ + +public class Grep { + + String[] stringArray; + /** + * Takes String array as character sequence for matching the pattern. + */ + public Grep (String[] stringArray) { + this.stringArray = stringArray; + } + + /** + * Returns number of non-interleaved occurences of groups which match the pattern. + */ + public int find (String regExpPattern) { + if (regExpPattern.length() == 0) { + throw new Failure("Empty string as input parameter for Grep.find(regExpPattern) method"); + } + Pattern pattern = Pattern.compile(regExpPattern); + int counter = 0; + for (int i = 0; i < stringArray.length; i++) { + + String string = stringArray[i]; + if (string != null) { + // Create matcher for this string + Matcher matcher = pattern.matcher(string); + + // Find all non-interleaved occurences of pattern in this string + for (int ind = 0; ind < string.length(); ) { + if (matcher.find(ind)) { + counter++; + ind = matcher.end(); + } else { + break; + } + } + } + } + return counter; + } + + /** + * Returns first string of stringArray with group which matches + * the pattern or empty string othrewise. + */ + public String findFirst (String regExpPattern) { + if (regExpPattern.length() == 0) { + throw new Failure("Empty string as input parameter for Grep.findFirst(regExpPattern) method"); + } + Pattern pattern = Pattern.compile(regExpPattern); + String result = ""; + for (int i = 0; i < stringArray.length; i++) { + + String string = stringArray[i]; + if (string != null) { + // Create matcher for this string + Matcher matcher = pattern.matcher(string); + if (matcher.find()) { + result = string; + break; + } + } + } + return result; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Harakiri.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Harakiri.java new file mode 100644 index 00000000000..8993a8665b2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Harakiri.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * Harakiri is used to terminate a stress test with PASS exit status + * before the test is terminated as timed out (and so failed). + * + *

      Harakiri class holds a thread which sleeps for the given amount + * of time, and then wakes up and executes System.exit() + * with the given exit status. That thread is daemon, so it doesn't + * prevent application from exiting once all its threads finish + * before it's time for harakiri. Appointing harakiri in zero + * delay implies immediate exit(). + * + *

      There is a limitation: you may appoint no more than one harakiri + * per application. + */ +public class Harakiri { + /** + * Use specific appoint() method to appoint harakiri. + * + * @see #appoint(int) + * @see #appoint(int,int) + */ + protected Harakiri() {} + + /** + * One harakiri per application, or null (by default). + */ + private static Thread harakiri = null; + + /** + *

      Return timeout (or waittime) value munus the margin + * value (which is assumed 1 minute by default). + * + *

      Treat args[0] as $TIMEOUT value, or seek for + * -waittime=$WAITTIME value. If both parameters + * (or either none of them) are assigned, throw an exception to + * report parameters inconsistency. + * + *

      Also, seek for -margin=... assignment, or assume margin + * is 1 minute. + * + * @param args Is usually obtained via the application's command-line. + * + * @throws IllegalArgumentException If args[] is inconsistent. + * + * @see #appoint(int) + * @see #appoint(int,int) + */ + public static int parseAppointment(String args[]) { + int timeout=-1, margin=1; + int timeouts=0, waittimes=0, margins=0; + for (int i=0; i 1) + throw new IllegalArgumentException( + "more than one -waittime=... is set"); + if (margins > 1) + throw new IllegalArgumentException( + "more than one -margin=... is set"); + + int result = timeout - margin; + if (result <= 0) + throw new IllegalArgumentException( + "delay appointment must be greater than "+margin+" minutes"); + return result; + } + + /** + * Appoint harakiri after the given amount of minutes, + * so that exit status would be 95 (to simulate JCK-like PASS + * status). + * + * @throws IllegalStateException If harakiri is already appointed. + * + * @see #appoint(int,int) + * @see #parseAppointment(String[]) + */ + public static void appoint(int minutes) { + appoint(minutes,95); // JCK-like PASS status + } + + /** + * Appoint Harakiri for the given amount of minutes, + * so that the given status would be exited when time + * is over. + * + * @throws IllegalStateException If harakiri is already appointed. + * + * @see #appoint(int) + * @see #parseAppointment(String[]) + */ + public static void appoint(int minutes, int status) { + if (harakiri != null) + throw new IllegalStateException("Harakiri is already appointed."); + + final long timeToExit = System.currentTimeMillis() + 60*1000L*minutes; + final int exitStatus = status; + + harakiri = new Thread(Harakiri.class.getName()) { + public void run() { + long timeToSleep = timeToExit - System.currentTimeMillis(); + if (timeToSleep > 0) + try { + // + // Use wait() instead of sleep(), because Java 2 + // specification doesn't guarantee the method + // sleep() to yield to other threads. + // + Object someDummyObject = new Object(); + synchronized (someDummyObject) { + someDummyObject.wait(timeToSleep); + } + } catch (InterruptedException exception) { + exception.printStackTrace(System.err); + // + // OOPS, the dagger for harakiri looks broken: + // + return; + }; + // + // OK, lets do it now: + // + System.err.println( + "#\n# Harakiri: prescheduled program termination.\n#"); + System.exit(exitStatus); // harakiri to all threads + } + }; + + harakiri.setPriority(Thread.MAX_PRIORITY); + harakiri.setDaemon(true); + harakiri.start(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java b/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java new file mode 100644 index 00000000000..31fbf1a231d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.*; + +/** + * This class implements a thread transfering bytes from + * a given InputStream to a given OutputStream. + */ +public class IORedirector extends Thread { + private BufferedReader bin = null; + private PrintStream pout = null; + private Log log = null; + + /** + * Few symbols to precede every text line being redirected. + */ + private String prefix = ""; + + /** + * Input and output streams must be specified. + */ + private IORedirector() { + super("IORedirector"); + } + + /** + * Redirect in to out. + * + * @deprecated Use newer constructor. + * + * @see #IORedirector(BufferedReader,Log,String) + */ + public IORedirector(InputStream in, OutputStream out) { + this(); + bin = new BufferedReader(new InputStreamReader(in)); + pout = new PrintStream(out); + } + + /** + * Redirect in to log; and assign + * few prefix symbols to precede each text line + * being redirected. + */ + public IORedirector(BufferedReader in, Log log, String prefix) { + this(); + this.prefix = prefix; + this.bin = in; + this.log = log; + } + + /** + * Set the prefix for redirected messages; + */ + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + private boolean cancelled = false; + private boolean stopped = false; + private boolean started = false; + + /** + * Signal to run() method that it should terminate, + * and wait until it is finished. + */ + public void cancel () { + cancelled = true; + while (this.isAlive()) + try { + this.join(); + } catch (InterruptedException ie) { + throw new Failure(ie); + }; + // stopped==true here. + } + + /** + * Pass data bytes from in to out stream + * until EOF is read, or this IORedirector is cancelled. + */ + public void run () { + started = true; + String logPrefix = "IORedirector-" + prefix; + if (bin == null || (pout == null && log == null)) + return; + try { + while (!cancelled) { + String line = bin.readLine(); + if (line == null) + break; //EOF + String message = prefix + line; + if (log != null) { + // It's synchronized and auto-flushed: + log.println(message); + } else if (pout != null) { + synchronized (pout) { + pout.println(message); + pout.flush(); + } + } + } + } catch (IOException e) { + // e.printStackTrace(log.getOutStream()); + String msg = "# WARNING: Caught IOException while redirecting output stream:\n\t" + e; + if (log != null) { + log.println(msg); + } else if (pout != null) { + synchronized (pout) { + pout.println(msg); + pout.flush(); + } + } else { + System.err.println(msg); + System.err.flush(); + } + }; + stopped = true; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.c b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.c new file mode 100644 index 00000000000..f256a338636 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmdi.h" +#include "JVMDITools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +char const *TranslateEvent(jint kind) { + switch (kind) { + case JVMDI_EVENT_SINGLE_STEP: + return ("JVMDI_EVENT_SINGLE_STEP"); + case JVMDI_EVENT_BREAKPOINT: + return ("JVMDI_EVENT_BREAKPOINT"); + case JVMDI_EVENT_FRAME_POP: + return ("JVMDI_EVENT_FRAME_POP"); + case JVMDI_EVENT_EXCEPTION: + return ("JVMDI_EVENT_EXCEPTION"); + case JVMDI_EVENT_USER_DEFINED: + return ("JVMDI_EVENT_USER_DEFINED"); + case JVMDI_EVENT_THREAD_START: + return ("JVMDI_EVENT_THREAD_START"); + case JVMDI_EVENT_THREAD_END: + return ("JVMDI_EVENT_THREAD_END"); + case JVMDI_EVENT_CLASS_PREPARE: + return ("JVMDI_EVENT_CLASS_PREPARE"); + case JVMDI_EVENT_CLASS_UNLOAD: + return ("JVMDI_EVENT_CLASS_UNLOAD"); + case JVMDI_EVENT_CLASS_LOAD: + return ("JVMDI_EVENT_CLASS_LOAD"); + case JVMDI_EVENT_FIELD_ACCESS: + return ("JVMDI_EVENT_FIELD_ACCESS"); + case JVMDI_EVENT_FIELD_MODIFICATION: + return ("JVMDI_EVENT_FIELD_MODIFICATION"); + case JVMDI_EVENT_EXCEPTION_CATCH: + return ("JVMDI_EVENT_EXCEPTION_CATCH"); + case JVMDI_EVENT_METHOD_ENTRY: + return ("JVMDI_EVENT_METHOD_ENTRY"); + case JVMDI_EVENT_METHOD_EXIT: + return ("JVMDI_EVENT_METHOD_EXIT"); + case JVMDI_EVENT_VM_INIT: + return ("JVMDI_EVENT_VM_INIT"); + case JVMDI_EVENT_VM_DEATH: + return ("JVMDI_EVENT_VM_DEATH"); + default: + return (""); + } +} + +char const *TranslateError(jvmdiError err) { + switch (err) { + case JVMDI_ERROR_NONE: + return ("JVMDI_ERROR_NONE"); + case JVMDI_ERROR_OUT_OF_MEMORY: + return ("JVMDI_ERROR_OUT_OF_MEMORY"); + case JVMDI_ERROR_ACCESS_DENIED: + return ("JVMDI_ERROR_ACCESS_DENIED"); + case JVMDI_ERROR_UNATTACHED_THREAD: + return ("JVMDI_ERROR_UNATTACHED_THREAD"); + case JVMDI_ERROR_VM_DEAD: + return ("JVMDI_ERROR_VM_DEAD"); + case JVMDI_ERROR_INTERNAL: + return ("JVMDI_ERROR_INTERNAL"); + case JVMDI_ERROR_INVALID_THREAD: + return ("JVMDI_ERROR_INVALID_THREAD"); + case JVMDI_ERROR_INVALID_FIELDID: + return ("JVMDI_ERROR_INVALID_FIELDID"); + case JVMDI_ERROR_INVALID_METHODID: + return ("JVMDI_ERROR_INVALID_METHODID"); + case JVMDI_ERROR_INVALID_LOCATION: + return ("JVMDI_ERROR_INVALID_LOCATION"); + case JVMDI_ERROR_INVALID_FRAMEID: + return ("JVMDI_ERROR_INVALID_FRAMEID"); + case JVMDI_ERROR_NO_MORE_FRAMES: + return ("JVMDI_ERROR_NO_MORE_FRAMES"); + case JVMDI_ERROR_OPAQUE_FRAME: + return ("JVMDI_ERROR_OPAQUE_FRAME"); + case JVMDI_ERROR_NOT_CURRENT_FRAME: + return ("JVMDI_ERROR_NOT_CURRENT_FRAME"); + case JVMDI_ERROR_TYPE_MISMATCH: + return ("JVMDI_ERROR_TYPE_MISMATCH"); + case JVMDI_ERROR_INVALID_SLOT: + return ("JVMDI_ERROR_INVALID_SLOT"); + case JVMDI_ERROR_DUPLICATE: + return ("JVMDI_ERROR_DUPLICATE"); + case JVMDI_ERROR_THREAD_NOT_SUSPENDED: + return ("JVMDI_ERROR_THREAD_NOT_SUSPENDED"); + case JVMDI_ERROR_THREAD_SUSPENDED: + return ("JVMDI_ERROR_THREAD_SUSPENDED"); + case JVMDI_ERROR_INVALID_OBJECT: + return ("JVMDI_ERROR_INVALID_OBJECT"); + case JVMDI_ERROR_INVALID_CLASS: + return ("JVMDI_ERROR_INVALID_CLASS"); + case JVMDI_ERROR_CLASS_NOT_PREPARED: + return ("JVMDI_ERROR_CLASS_NOT_PREPARED"); + case JVMDI_ERROR_NULL_POINTER: + return ("JVMDI_ERROR_NULL_POINTER"); + case JVMDI_ERROR_ABSENT_INFORMATION: + return ("JVMDI_ERROR_ABSENT_INFORMATION"); + case JVMDI_ERROR_INVALID_EVENT_TYPE: + return ("JVMDI_ERROR_INVALID_EVENT_TYPE"); + case JVMDI_ERROR_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_NOT_IMPLEMENTED"); + case JVMDI_ERROR_INVALID_THREAD_GROUP: + return ("JVMDI_ERROR_INVALID_THREAD_GROUP"); + case JVMDI_ERROR_INVALID_PRIORITY: + return ("JVMDI_ERROR_INVALID_PRIORITY"); + case JVMDI_ERROR_NOT_FOUND: + return ("JVMDI_ERROR_NOT_FOUND"); + case JVMDI_ERROR_INVALID_MONITOR: + return ("JVMDI_ERROR_INVALID_MONITOR"); + case JVMDI_ERROR_ILLEGAL_ARGUMENT: + return ("JVMDI_ERROR_ILLEGAL_ARGUMENT"); + case JVMDI_ERROR_NOT_MONITOR_OWNER: + return ("JVMDI_ERROR_NOT_MONITOR_OWNER"); + case JVMDI_ERROR_INTERRUPT: + return ("JVMDI_ERROR_INTERRUPT"); + case JVMDI_ERROR_INVALID_TYPESTATE: + return ("JVMDI_ERROR_INVALID_TYPESTATE"); + case JVMDI_ERROR_INVALID_CLASS_FORMAT: + return ("JVMDI_ERROR_INVALID_CLASS_FORMAT"); + case JVMDI_ERROR_CIRCULAR_CLASS_DEFINITION: + return ("JVMDI_ERROR_CIRCULAR_CLASS_DEFINITION"); + case JVMDI_ERROR_ADD_METHOD_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_ADD_METHOD_NOT_IMPLEMENTED"); + case JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED"); + case JVMDI_ERROR_FAILS_VERIFICATION: + return ("JVMDI_ERROR_FAILS_VERIFICATION"); +#ifdef JVMDI_VERSION_1_2 + case JVMDI_ERROR_UNSUPPORTED_VERSION: + return ("JVMDI_ERROR_UNSUPPORTED_VERSION"); + case JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED"); + case JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED"); + case JVMDI_ERROR_NAMES_DONT_MATCH: + return ("JVMDI_ERROR_NAMES_DONT_MATCH"); + case JVMDI_ERROR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED"); + case JVMDI_ERROR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED: + return ("JVMDI_ERROR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED"); +#endif + default: + return (""); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.h b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.h new file mode 100644 index 00000000000..6f27c19024d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +char const *TranslateEvent(jint kind); +char const *TranslateError(jvmdiError err); + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c new file mode 100644 index 00000000000..b6afbf8783d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c @@ -0,0 +1,1276 @@ +/* + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * JVMTI agent used for run every test from the testbase in a special + * debug mode. This mode is intended to be part of serviceability + * reliability testing. + */ + +#include +#include +#include +#include +#include + +#include "nsk_tools.h" +#include "jni_tools.h" +#include "JVMTITools.h" +#include "jvmti_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = NULL; /* JVMTI env */ +static jvmtiEventCallbacks callbacks; +static jrawMonitorID eventLock; /* raw monitor used for exclusive ownership of HotSwap function */ + +static volatile int debug_mode = 0; /* 0 - verbose mode off; + 1 - verbose mode on; + 2 - verbose mode on including all JVMTI events reporting, + produces a huge number of messages */ + +/* stress level */ +static volatile int stress_lev = 0; /* 0 - default mode: generation of all events except + ExceptionCatch, + MethodEntry/Exit, SingleStep; + 1 - generation of all events except + MethodEntry/Exit, + SingleStep; + 2 - generation of all events except + SingleStep; + 3 - generation of all events, including + ExceptionCatch, + MethodEntry/Exit, + SingleStep + */ + +#define TRUE 1 +#define FALSE 0 + +/**** the following is used for "postVM_DEATH" events watching ****/ +static volatile int vm_death_occured = FALSE; +/************************************************/ + +/**** the following is used for HotSwap mode ****/ + +/* HotSwap modes: + HOTSWAP_OFF - default mode: HotSwap off; + HOTSWAP_EVERY_METHOD_ENTRY - HotSwap tested class in every method entry event + of running test + HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS - HotSwap tested class in every + method entry event of every class + HOTSWAP_EVERY_SINGLE_STEP - HotSwap tested class in every single step event + of running test + HOTSWAP_EVERY_EXCEPTION - HotSwap tested class in every exception event + of running test + HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS - HotSwap tested class in every + exception event of every class + */ + +#define HOTSWAP_OFF 0 +#define HOTSWAP_EVERY_METHOD_ENTRY 2 +#define HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS 20 +#define HOTSWAP_EVERY_SINGLE_STEP 3 +#define HOTSWAP_EVERY_EXCEPTION 4 +#define HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS 40 + +static int hotswap = HOTSWAP_OFF; + +typedef struct { /* test class info */ + char *clazzsig; /* class signature */ + jclass cls; /* a class to be redefined */ + jint bCount; /* number of bytes defining the class */ + jbyte *clsBytes; /* bytes defining the class */ + struct class_info *next; +} class_info; + + +static const char *shortTestName = NULL; /* name of the test without package prefix */ +static jclass rasCls; /* reference to the auxiliary class RASagent used for HotSwap */ +static class_info *clsInfo = NULL, *clsInfoFst = NULL; + +static void lock(JNIEnv*); +static void unlock(JNIEnv*); +static jint allocClsInfo(JNIEnv*, char*, jclass); +static void deallocClsInfo(JNIEnv*); +static int findAndHotSwap(JNIEnv*, jclass); +static int doHotSwap(JNIEnv*, jclass, jint, jbyte*); +static void display(int, const char format[], ...); +static void clearJavaException(JNIEnv*); +static int enableEventsCaps(); +static int addStressEvents(); +static void getVerdict(JNIEnv*, const char *); +/************************************************/ + +/** callback functions **/ +void JNICALL +Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, jmethodID method, + jlocation loc) { + + display(1, "#### JVMTIagent: Breakpoint occurred ####\n"); + + getVerdict(jni_env, "Breakpoint"); +} + +void JNICALL +ClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jclass class_beeing_redefined, + jobject loader, const char* name, jobject protection_domain, + jint class_data_len, const unsigned char* class_data, + jint *new_class_data_len, unsigned char** new_class_data) { + + display(1, "#### JVMTIagent: ClassFileLoadHook occurred ####\n"); + + getVerdict(jni_env, "ClassFileLoadHook"); +} + +void JNICALL +ClassLoad(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jclass klass) { + char *cls_sig; + jint clsByteCount; + + display((hotswap != HOTSWAP_OFF)?0:1, + "#### JVMTIagent: ClassLoad occurred ####\n"); + + getVerdict(jni_env, "ClassLoad"); + + if (hotswap != HOTSWAP_OFF) { + /* enter into a raw monitor for exclusive work with redefined class */ + lock(jni_env); + display(0, "#### JVMTIagent: ClassLoad: >>>>>>>> entered the raw monitor \"eventLock\" ####\n"); + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature, + jvmti_env, klass, &cls_sig, /*&generic*/NULL))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to get class signature\n"); + else { + if (shortTestName != NULL) { + if (strstr((const char*) cls_sig, shortTestName) != NULL) { + display(0, "#### JVMTIagent: found test class matched with \"%s\"\n\ +\tsignature=%s\n", + shortTestName, cls_sig); + clsByteCount = allocClsInfo(jni_env, cls_sig, klass); + display(0, "#### JVMTIagent: %d bytes defining the class have been successfully loaded\n", + clsByteCount); + } + } + } + + /* exit from the raw monitor */ + unlock(jni_env); + display(0, "#### JVMTIagent: ClassLoad: <<<<<<<< exited from the raw monitor \"eventLock\" ####\n\n"); + } +} + +void JNICALL +ClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jthread thr, jclass cls) { + + display(1, "#### JVMTIagent: ClassPrepare occurred ####\n"); + + getVerdict(jni_env, "ClassPrepare"); +} + +void JNICALL +CompiledMethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size, + const void* code_addr, jint map_length, + const jvmtiAddrLocationMap* map, const void* compile_info) { + + display(1, "#### JVMTIagent: CompiledMethodLoad occurred ####\n"); + + getVerdict(NULL, "CompiledMethodLoad"); +} + +void JNICALL +CompiledMethodUnload(jvmtiEnv *jvmti_env, jmethodID method, + const void* code_addr) { + + display(1, "#### JVMTIagent: CompiledMethodUnload occurred ####\n"); + + getVerdict(NULL, "CompiledMethodUnload"); +} + +void JNICALL +DataDumpRequest(jvmtiEnv *jvmti_env) { + + display(1, "#### JVMTIagent: DataDumpRequest occurred ####\n"); + + getVerdict(NULL, "DataDumpRequest"); +} + +void JNICALL +DynamicCodeGenerated(jvmtiEnv *jvmti_env, + const char* name, + const void* address, + jint length) { + + display(1, "#### JVMTIagent: DynamicCodeGenerated occurred ####\n"); + + getVerdict(NULL, "DynamicCodeGenerated"); +} + +void JNICALL +Exception(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, + jmethodID method, jlocation location, jobject exception, + jmethodID catch_method, jlocation catch_location) { + jclass decl_clazz; + + display((hotswap == HOTSWAP_EVERY_EXCEPTION || + hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS)?0:1, + "#### JVMTIagent: Exception occurred ####\n"); + + getVerdict(jni_env, "Exception"); + + if (hotswap == HOTSWAP_EVERY_EXCEPTION || + hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) { + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, + jvmti_env, method, &decl_clazz))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to get method declaring class\n"); + + if (findAndHotSwap(jni_env, decl_clazz) != 0) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to hotswap class\n"); + } +} + +void JNICALL +FieldAccess(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jthread thr, jmethodID method, + jlocation location, jclass field_klass, jobject obj, jfieldID field) { + + display(1, "#### JVMTIagent: FieldAccess occurred ####\n"); + + getVerdict(jni_env, "FieldAccess"); +} + +void JNICALL +FieldModification(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jthread thr, jmethodID method, jlocation location, + jclass field_klass, jobject obj, + jfieldID field, char sig, jvalue new_value) { + + display(1, "#### JVMTIagent: FieldModification occurred ####\n"); + + getVerdict(jni_env, "FieldModification"); +} + +void JNICALL +FramePop(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jthread thr, jmethodID method, jboolean wasPopedByException) { + + display(1, "#### JVMTIagent: FramePop occurred ####\n"); + + getVerdict(jni_env, "FramePop"); +} + +void JNICALL +GarbageCollectionFinish(jvmtiEnv *jvmti_env) { + + display(1, "#### JVMTIagent: GarbageCollectionFinish occurred ####\n"); + + getVerdict(NULL, "GarbageCollectionFinish"); +} + +void JNICALL +GarbageCollectionStart(jvmtiEnv *jvmti_env) { + + display(1, "#### JVMTIagent: GarbageCollectionStart occurred ####\n"); + + getVerdict(NULL, "GarbageCollectionStart"); +} + +void JNICALL +MonitorContendedEnter(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, + jobject obj) { + + display(1, "#### JVMTIagent: MonitorContendedEnter occurred ####\n"); + + getVerdict(jni_env, "MonitorContendedEnter"); +} + +void JNICALL +MonitorContendedEntered(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, + jobject obj) { + + display(1, "#### JVMTIagent: MonitorContendedEntered occurred ####\n"); + + getVerdict(jni_env, "MonitorContendedEntered"); +} + +void JNICALL +MonitorWait(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, jobject obj, + jlong tout) { + + display(1, "#### JVMTIagent: MonitorWait occurred ####\n"); + + getVerdict(jni_env, "MonitorWait"); +} + +void JNICALL +MonitorWaited(jvmtiEnv *jvmti_env, JNIEnv* jni_env, + jthread thr, jobject obj, jboolean timed_out) { + + display(1, "#### JVMTIagent: MonitorWaited occurred ####\n"); + + getVerdict(jni_env, "MonitorWaited"); +} + +void JNICALL +NativeMethodBind(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, + jmethodID method, void *addr, void **new_addr) { + + display(1, "#### JVMTIagent: NativeMethodBind occurred ####\n"); + + getVerdict(jni_env, "NativeMethodBind"); +} + +void JNICALL +ObjectFree(jvmtiEnv *jvmti_env, jlong tag) { + + display(1, "#### JVMTIagent: ObjectFree occurred ####\n"); + + getVerdict(NULL, "ObjectFree"); +} + +void JNICALL +ThreadEnd(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread) { + + display(1, "#### JVMTIagent: ThreadEnd occurred ####\n"); + + getVerdict(jni_env, "ThreadEnd"); +} + +void JNICALL +ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread) { + + display(1, "#### JVMTIagent: ThreadStart occurred ####\n"); + + getVerdict(jni_env, "ThreadStart"); +} + +void JNICALL +VMDeath(jvmtiEnv *jvmti_env, JNIEnv *jni_env) { + vm_death_occured = TRUE; + + display(0, "#### JVMTIagent: VMDeath occurred ####\n"); + + if (hotswap != HOTSWAP_OFF) { + deallocClsInfo(jni_env); + display(0, "#### JVMTIagent: allocated memory was successfully freed ####\n"); + } +} + +void JNICALL +VMInit(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr) { + + display(0, "#### JVMTIagent: VMInit occurred ####\n"); + + getVerdict(jni_env, "VMInit"); +} + +void JNICALL +VMStart(jvmtiEnv *jvmti_env, JNIEnv* jni_env) { + + display(0, "#### JVMTIagent: VMStart occurred ####\n"); + + getVerdict(jni_env, "VMStart"); +} + +JNIEXPORT void JNICALL +VMObjectAlloc(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, + jobject object, jclass object_klass, jlong size) { + + display(1, "#### JVMTIagent: VMObjectAlloc occurred ####\n"); + + getVerdict(jni_env, "VMObjectAlloc"); +} + +void JNICALL +SingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, + jmethodID method, jlocation location) { + jclass decl_clazz; + + display((hotswap == HOTSWAP_EVERY_SINGLE_STEP)?0:1, + "#### JVMTIagent: SingleStep occurred ####\n"); + + getVerdict(jni_env, "SingleStep"); + + if (hotswap == HOTSWAP_EVERY_SINGLE_STEP) { + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, + jvmti_env, method, &decl_clazz))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to get method declaring class\n"); + + if (findAndHotSwap(jni_env, decl_clazz) != 0) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to hotswap class\n"); + } +} + +void JNICALL +MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jthread thr, jmethodID method) { + jclass decl_clazz; + + display((hotswap == HOTSWAP_EVERY_METHOD_ENTRY || + hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS)?0:1, + "#### JVMTIagent: MethodEntry occurred ####\n"); + + getVerdict(jni_env, "MethodEntry"); + + if (hotswap == HOTSWAP_EVERY_METHOD_ENTRY || + hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS) { + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, + jvmti_env, method, &decl_clazz))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to get method declaring class\n"); + + if (findAndHotSwap(jni_env, decl_clazz) != 0) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to hotswap class\n"); + } +} + +void JNICALL +MethodExit(jvmtiEnv *jvmti_env, JNIEnv *jni_env, + jthread thr, jmethodID method, + jboolean was_poped_by_exc, jvalue return_value) { + + display(1, "#### JVMTIagent: MethodExit occurred ####\n"); + + getVerdict(jni_env, "MethodExit"); +} + +void JNICALL +ExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, + jmethodID method, jlocation location, jobject exception) { + jclass decl_clazz; + + display((hotswap == HOTSWAP_EVERY_EXCEPTION || + hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS)?0:1, + "#### JVMTIagent: ExceptionCatch occurred ####\n"); + + getVerdict(jni_env, "ExceptionCatch"); + + if (hotswap == HOTSWAP_EVERY_EXCEPTION || + hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) { + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, + jvmti_env, method, &decl_clazz))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to get method declaring class\n"); + + if (findAndHotSwap(jni_env, decl_clazz) != 0) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to hotswap class\n"); + } +} +/************************/ + +static void lock(JNIEnv *jni_env) { + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, + jvmti, eventLock))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to enter a raw monitor\n"); +} + +static void unlock(JNIEnv *jni_env) { + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, + jvmti, eventLock))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to exit a raw monitor\n"); +} + +JNIEXPORT jint JNICALL +Java_nsk_share_RASagent_setHotSwapMode(JNIEnv *jni_env, jclass cls, + jboolean vrb, jint level, jstring shortName) { + jvmtiCapabilities capabil; + jmethodID mid = NULL; + + if (jvmti == NULL) { + printf("ERROR(%s,%d): JVMTIagent was not properly loaded: JVMTI env = NULL\n", + __FILE__, __LINE__); + return 1; + } + + /* get supported JVMTI capabilities */ + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities, + jvmti, &capabil))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to get capabilities\n"); + if (capabil.can_redefine_classes != 1) { /* ???????????? */ + printf("ERROR: JVMTIagent: Class File Redefinition (HotSwap) is not implemented in this VM\n"); + return 1; + } + + if (vrb == JNI_TRUE && debug_mode == 0) + debug_mode = 1; + + hotswap = level; + switch (hotswap) { + case HOTSWAP_OFF: + display(0, "#### JVMTIagent: hotswap mode off ####\n"); + return 0; + case HOTSWAP_EVERY_METHOD_ENTRY: + stress_lev = 2; + display(0, "#### JVMTIagent: hotswapping class in every method entry event enabled ####\n\ +\tHotSwap stress level: %d\n", + stress_lev); + break; + case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS: + stress_lev = 2; + display(0, "#### JVMTIagent: hotswapping class in every method entry event for every class enabled ####\n\ +\tHotSwap stress level: %d\n", + stress_lev); + break; + case HOTSWAP_EVERY_SINGLE_STEP: + stress_lev = 3; + display(0, "#### JVMTIagent: hotswapping class in every single step event enabled ####\n\ +\tHotSwap stress level: %d\n", + stress_lev); + break; + case HOTSWAP_EVERY_EXCEPTION: + stress_lev = 4; + display(0, "#### JVMTIagent: hotswapping class in every exception event enabled ####\n\ +\tHotSwap stress level: %d\n", + stress_lev); + break; + case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS: + stress_lev = 40; + display(0, "#### JVMTIagent: hotswapping class in every exception event for every class enabled ####\n\ +\tHotSwap stress level: %d\n", + stress_lev); + break; + default: + printf("ERROR(%s,%d): JVMTIagent: unknown value of HotSwap stress level: \"%d\"\n", + __FILE__,__LINE__,hotswap); + return 1; + } + + if (!NSK_JNI_VERIFY(jni_env, (shortTestName = NSK_CPP_STUB3(GetStringUTFChars, + jni_env, shortName, NULL)) != NULL)) { + printf("ERROR: JVMTIagent: unable to get UTF-8 characters of the string\n"); + return 1; + } + display(0, "#### JVMTIagent: short name of current test is \"%s\"\n", + shortTestName); + + if (!NSK_JNI_VERIFY(jni_env, (rasCls = NSK_CPP_STUB2(NewGlobalRef, + jni_env, cls)) != NULL)) { + printf("ERROR JVMTIagent: unable to create a new global reference of the class \"RASagent\"\n"); + return 1; + } + + if (addStressEvents() != 0) { + printf("ERROR(%s,%d): JVMTIagent terminated abnormally! ####\n", + __FILE__,__LINE__); + return 1; + } + + return 0; +} + +static jint allocClsInfo(JNIEnv *jni_env, char *cls_sig, jclass clazz) { + class_info *_clsInfo = NULL; + jmethodID mid = NULL; + jbyteArray classBytes; + jboolean isCopy; + + if ((_clsInfo = (class_info*) + malloc(sizeof(class_info))) == NULL) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: cannot allocate memory for class_info\n"); + + /* fill the structure class_info */ + _clsInfo->clazzsig = cls_sig; + + if (!NSK_JNI_VERIFY(jni_env, ((*_clsInfo).cls = NSK_CPP_STUB2(NewGlobalRef, + jni_env, clazz)) != NULL)) { + printf("ERROR: JVMTIagent: unable to create a new global reference of class \"%s\"\n", + _clsInfo->clazzsig); + free(_clsInfo); + deallocClsInfo(jni_env); + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: unable to create a new global reference of class\n"); + } + + if (!NSK_JNI_VERIFY(jni_env, (mid = + NSK_CPP_STUB4(GetStaticMethodID, jni_env, rasCls, + "loadFromClassFile", "(Ljava/lang/String;)[B")) != NULL)) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: unable to get ID of the method \"loadFromClassFile\"\n"); + + classBytes = (jbyteArray) NSK_CPP_STUB4(CallStaticObjectMethod, + jni_env, rasCls, mid, NSK_CPP_STUB2(NewStringUTF, jni_env, cls_sig)); + + clearJavaException(jni_env); + + (*_clsInfo).bCount = NSK_CPP_STUB2(GetArrayLength, jni_env, classBytes); + + (*_clsInfo).clsBytes = + NSK_CPP_STUB3(GetByteArrayElements, jni_env, classBytes, &isCopy); + + _clsInfo->next = NULL; + + if (clsInfo != NULL) { + clsInfo->next = (struct class_info*) _clsInfo; + } + else { + clsInfoFst = _clsInfo; + } + clsInfo = _clsInfo; + + return (*_clsInfo).bCount; +} + +static void deallocClsInfo(JNIEnv *jni_env) { + class_info *clsInfoCurr = clsInfoFst; + + NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni_env, rasCls)); + + while(clsInfoCurr != NULL) { + class_info *_clsInfo = clsInfoCurr; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, + jvmti, (unsigned char*) clsInfoCurr->clazzsig))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: failed to deallocate memory for clazzsig\n"); + + NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni_env, clsInfoCurr->cls)); + + clsInfoCurr = (class_info*) clsInfoCurr->next; + + free(_clsInfo); + } + /* fix for 4756585: indicate that stucture class_info is empty now */ + clsInfoFst = NULL; +} + +static int findAndHotSwap(JNIEnv *jni_env, jclass clazz) { + int ret_code = 0; + char *clazzsig = NULL; + class_info *clsInfoCurr = clsInfoFst; + + display(1, "\n#### JVMTIagent: findAndHotSwap: obtaining class signature of class to be hotswap ...\n"); + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature, + jvmti, clazz, &clazzsig, /*&generic*/NULL))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: findAndHotSwap: failed to get class signature\n"); + else { + display(1, "#### JVMTIagent: findAndHotSwap: ... class signature obtained: \"%s\"\n", + clazzsig); + + /* enter into a raw monitor for exclusive work with redefined class */ + lock(jni_env); + display(0, "#### JVMTIagent: findAndHotSwap: >>>>>>>> entered the raw monitor \"eventLock\" ####\n"); + + while(clsInfoCurr != NULL) { + if (hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS || + hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) { + display(1, "\n#### JVMTIagent: findAndHotSwap: going to hotswap tested class \"%s\" during execution of class \"%s\" ...\n", + clsInfoCurr->clazzsig, clazzsig); + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, + jvmti, (unsigned char*) clazzsig))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: findAndHotSwap: failed to deallocate memory for clazzsig\n"); + + if (doHotSwap(jni_env, clsInfoCurr->cls, + clsInfoCurr->bCount, clsInfoCurr->clsBytes) != 0) { + ret_code = 1; + break; + } + } + else { + if (strcmp(clazzsig, clsInfoCurr->clazzsig) == 0) { + display(0, "\n#### JVMTIagent: findAndHotSwap: tested class found \"%s\" ...\n", + clazzsig); + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, + jvmti, (unsigned char*) clazzsig))) + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: findAndHotSwap: failed to deallocate memory for clazzsig\n"); + + display(0, "\n#### JVMTIagent: findAndHotSwap: going to hotswap tested class \"%s\" ...\n", + clsInfoCurr->clazzsig); + if (doHotSwap(jni_env, clsInfoCurr->cls, + clsInfoCurr->bCount, clsInfoCurr->clsBytes) != 0) { + ret_code = 1; + break; + } + } + } + + clsInfoCurr = (class_info*) clsInfoCurr->next; + } + + /* exit raw monitor */ + unlock(jni_env); + display(0, "#### JVMTIagent: findAndHotSwap: <<<<<<<< exited from the raw monitor \"eventLock\" ####\n\n"); + } + + return ret_code; +} + +static int doHotSwap(JNIEnv *jni_env, jclass redefCls, jint bCount, + jbyte *classBytes) { + jvmtiClassDefinition classDef; + + /* fill the structure jvmtiClassDefinition */ + classDef.klass = redefCls; + classDef.class_byte_count = bCount; + classDef.class_bytes = (unsigned char*) classBytes; + + display(0, "#### JVMTIagent: >>>>>>>> Invoke RedefineClasses():\n\ +\tnew class byte count=%d\n", + classDef.class_byte_count); + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RedefineClasses, + jvmti, 1, &classDef))) + return 1; + + display(0, "#### JVMTIagent: <<<<<<<< RedefineClasses() is successfully done ####\n"); + + return 0; +} + +static int addStressEvents() { + static int stepEventSet = JNI_FALSE; + static int methodsEventSet = JNI_FALSE; + static int excCatchEventSet = JNI_FALSE; + + if (stress_lev >= 3) { + /* SingleStep events */ + if (stepEventSet == JNI_FALSE) { /* don't set the event twice */ + display(0, "#### JVMTIagent: setting SingleStep events ...\n"); + + callbacks.SingleStep = &SingleStep; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, NULL))) + return JNI_ERR; + + stepEventSet = JNI_TRUE; + + display(0, "#### JVMTIagent: ... setting SingleStep events done\n"); + } + } + + if (stress_lev >= 2) { + /* MethodEntry/Exit events */ + if (methodsEventSet == JNI_FALSE) { /* don't set the event twice */ + display(0, "#### JVMTIagent: setting MethodEntry events ...\n"); + + callbacks.MethodEntry = &MethodEntry; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL))) + return JNI_ERR; + + display(0, "#### JVMTIagent: ... setting MethodEntry events done\n"); + + /* MethodExit events */ + display(0, "#### JVMTIagent: setting MethodExit events ...\n"); + + callbacks.MethodExit = &MethodExit; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL))) + return JNI_ERR; + + display(0, "#### JVMTIagent: ... setting MethodExit events done\n"); + + methodsEventSet = JNI_TRUE; + } + } + + if (stress_lev >= 1) { + /* ExceptionCatch events */ + if (excCatchEventSet == JNI_FALSE) { /* don't set the event twice */ + display(0, "#### JVMTIagent: setting ExceptionCatch events ...\n"); + + callbacks.ExceptionCatch = &ExceptionCatch; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION_CATCH, NULL))) + return JNI_ERR; + + excCatchEventSet = JNI_TRUE; + + display(0, "#### JVMTIagent: ... setting ExceptionCatch events done\n"); + } + } + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, + jvmti, &callbacks, sizeof(callbacks)))) + return JNI_ERR; + else + return 0; +} + +static int enableEventsCaps() { + jvmtiCapabilities caps; + + memset(&caps, 0, sizeof(jvmtiCapabilities)); + + /* add all capabilities */ + caps.can_redefine_classes = 1; + caps.can_generate_breakpoint_events = 1; + caps.can_generate_all_class_hook_events = 1; + caps.can_generate_single_step_events = 1; + caps.can_generate_method_entry_events = 1; + caps.can_generate_method_exit_events = 1; + caps.can_generate_exception_events = 1; + caps.can_generate_compiled_method_load_events = 1; + caps.can_generate_field_access_events = 1; + caps.can_generate_field_modification_events = 1; + caps.can_generate_frame_pop_events = 1; + caps.can_generate_garbage_collection_events = 1; + caps.can_generate_monitor_events = 1; + caps.can_generate_native_method_bind_events = 1; + caps.can_generate_object_free_events = 1; + caps.can_generate_vm_object_alloc_events = 1; + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, + jvmti, &caps))) + return JNI_ERR; + + /* Breakpoint events */ + display(0, "#### JVMTIagent: setting Breakpoint events ...\n"); + + callbacks.Breakpoint = &Breakpoint; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting Breakpoint events done\n"); + + /* ClassFileLoadHook events */ + display(0, "#### JVMTIagent: setting ClassFileLoadHook events ...\n"); + + callbacks.ClassFileLoadHook = &ClassFileLoadHook; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting ClassFileLoadHook events done\n"); + + /* ClassLoad events */ + display(0, "#### JVMTIagent: setting ClassLoad events ...\n"); + + callbacks.ClassLoad = &ClassLoad; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting ClassLoad events done\n"); + + /* ClassPrepare events */ + display(0, "#### JVMTIagent: setting ClassPrepare events ...\n"); + + callbacks.ClassPrepare = &ClassPrepare; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting ClassPrepare events done\n"); + + /* CompiledMethodLoad events */ + display(0, "#### JVMTIagent: setting CompiledMethodLoad events ...\n"); + + callbacks.CompiledMethodLoad = &CompiledMethodLoad; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting CompiledMethodLoad events done\n"); + + /* CompiledMethodUnload events */ + display(0, "#### JVMTIagent: setting CompiledMethodUnload events ...\n"); + + callbacks.CompiledMethodUnload = &CompiledMethodUnload; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting CompiledMethodUnload events done\n"); + + /* DataDumpRequest events */ + display(0, "#### JVMTIagent: setting DataDumpRequest events ...\n"); + + callbacks.DataDumpRequest = &DataDumpRequest; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting DataDumpRequest events done\n"); + + /* DynamicCodeGenerated events */ + display(0, "#### JVMTIagent: setting DynamicCodeGenerated events ...\n"); + + callbacks.DynamicCodeGenerated = &DynamicCodeGenerated; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting DynamicCodeGenerated events done\n"); + + /* Exception events */ + display(0, "#### JVMTIagent: setting Exception events ...\n"); + + callbacks.Exception = &Exception; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting Exception events done\n"); + + /* FieldAccess events */ + display(0, "#### JVMTIagent: setting FieldAccess events ...\n"); + + callbacks.FieldAccess = &FieldAccess; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting FieldAccess events done\n"); + + /* FieldModification events */ + display(0, "#### JVMTIagent: setting FieldModification events ...\n"); + + callbacks.FieldModification = &FieldModification; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting FieldModification events done\n"); + + /* FramePop events */ + display(0, "#### JVMTIagent: setting FramePop events ...\n"); + + callbacks.FramePop = &FramePop; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting FramePop events done\n"); + + /* GarbageCollectionFinish events */ + display(0, "#### JVMTIagent: setting GarbageCollectionFinish events ...\n"); + + callbacks.GarbageCollectionFinish = &GarbageCollectionFinish; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting GarbageCollectionFinish events done\n"); + + /* GarbageCollectionStart events */ + display(0, "#### JVMTIagent: setting GarbageCollectionStart events ...\n"); + + callbacks.GarbageCollectionStart = &GarbageCollectionStart; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting GarbageCollectionStart events done\n"); + + /* MonitorContendedEnter events */ + display(0, "#### JVMTIagent: setting MonitorContendedEnter events ...\n"); + + callbacks.MonitorContendedEnter = &MonitorContendedEnter; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting MonitorContendedEnter events done\n"); + + /* MonitorContendedEntered events */ + display(0, "#### JVMTIagent: setting MonitorContendedEntered events ...\n"); + + callbacks.MonitorContendedEntered = &MonitorContendedEntered; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting MonitorContendedEntered events done\n"); + + /* MonitorWait events */ + display(0, "#### JVMTIagent: setting MonitorWait events ...\n"); + + callbacks.MonitorWait = &MonitorWait; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting MonitorWait events done\n"); + + /* MonitorWaited events */ + display(0, "#### JVMTIagent: setting MonitorWaited events ...\n"); + + callbacks.MonitorWaited = &MonitorWaited; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting MonitorWaited events done\n"); + + /* NativeMethodBind events */ + display(0, "#### JVMTIagent: setting NativeMethodBind events ...\n"); + + callbacks.NativeMethodBind = &NativeMethodBind; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting NativeMethodBind events done\n"); + + /* ObjectFree events */ + display(0, "#### JVMTIagent: setting ObjectFree events ...\n"); + + callbacks.ObjectFree = &ObjectFree; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting ObjectFree events done\n"); + + /* ThreadEnd events */ + display(0, "#### JVMTIagent: setting ThreadEnd events ...\n"); + + callbacks.ThreadEnd = &ThreadEnd; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting ThreadEnd events done\n"); + + /* ThreadStart events */ + display(0, "#### JVMTIagent: setting ThreadStart events ...\n"); + + callbacks.ThreadStart = &ThreadStart; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting ThreadStart events done\n"); + + /* VMDeath events */ + display(0, "#### JVMTIagent: setting VMDeath events ...\n"); + + callbacks.VMDeath = &VMDeath; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting VMDeath events done\n"); + + /* VMInit events */ + display(0, "#### JVMTIagent: setting VMInit events ...\n"); + + callbacks.VMInit = &VMInit; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting VMInit events done\n"); + + /* VMStart events */ + display(0, "#### JVMTIagent: setting VMStart events ...\n"); + + callbacks.VMStart = &VMStart; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting VMStart events done\n"); + + /* VMObjectAlloc events */ + display(0, "#### JVMTIagent: setting VMObjectAlloc events ...\n"); + + callbacks.VMObjectAlloc = &VMObjectAlloc; + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, + jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL))) + return JNI_ERR; + display(0, "#### JVMTIagent: ... setting VMObjectAlloc events done\n"); + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, + jvmti, &callbacks, sizeof(callbacks)))) + return JNI_ERR; + + return 0; +} + +static void clearJavaException(JNIEnv* jni_env) { + if (NSK_CPP_STUB1(ExceptionOccurred, jni_env)) { + + NSK_CPP_STUB1(ExceptionDescribe, jni_env); + NSK_CPP_STUB1(ExceptionClear, jni_env); + + NSK_CPP_STUB2(FatalError, jni_env, + "JVMTIagent: exception occurred in java code, aborting\n"); + } +} + +static int get_tok(char **src, char *buf, int buflen, char sep) { + int i; + char *p = *src; + for (i = 0; i < buflen; i++) { + if (p[i] == 0 || p[i] == sep) { + buf[i] = 0; + if (p[i] == sep) { + i++; + } + *src += i; + return i; + } + buf[i] = p[i]; + } + /* overflow */ + return 0; +} + +static void doSetup(char *str) { + if (str == 0) + str = ""; + + if ((strcmp(str, "help")) == 0) { + printf("#### JVMTIagent usage: -agentlib:JVMTIagent[=[help]|[=[verbose]|[verbose2],[stress0|stress1|stress2|stress3]]]\n"); + printf("#### where: help\tprint this message\n"); + printf("#### verbose\tturn verbose mode on\n"); + printf("#### verbose2\tturn extended verbose mode on (including reporting JVMTI events)\n"); + printf("#### stress0, or empty value\tturn stress level 0 on (default mode):\n"); + printf("#### enable event generation except ExceptionCatch, MethodEntry/Exit, SingleStep\n"); + printf("#### stress1\tturn stress level 1 on:\n"); + printf("#### enable generation of ExceptionCatch events\n"); + printf("#### stress2\tturn stress level 2 on:\n"); + printf("#### enable generation of ExceptionCatch,\n"); + printf("#### MethodEntry/Exit events\n"); + printf("#### stress3\tturn stress level 3 on:\n"); + printf("#### enable generation of ExceptionCatch,\n"); + printf("#### MethodEntry/Exit,\n"); + printf("#### SingleStep events\n"); + exit(1); + } + + while (*str) { + char buf[1000]; + + if (!get_tok(&str, buf, sizeof(buf), ',')) { + printf("ERROR: JVMTIagent: bad option: \"%s\"!\n", str); + exit(1); + } + if ((strcmp(buf, "verbose")) == 0) { + printf("#### JVMTIagent: turned verbose mode on ####\n"); + debug_mode = 1; + } + if ((strcmp(buf, "verbose2")) == 0) { + printf("#### JVMTIagent: turned extended verbose mode on ####\n"); + debug_mode = 2; + } + if ((strcmp(buf, "stress0")) == 0) { + if (debug_mode > 0) + printf("#### JVMTIagent: turned stress level 0 on ####\n"); + stress_lev = 0; + } + if ((strcmp(buf, "stress1")) == 0) { + if (debug_mode > 0) + printf("#### JVMTIagent: turned stress level 1 on ####\n"); + stress_lev = 1; + } + if ((strcmp(buf, "stress2")) == 0) { + if (debug_mode > 0) + printf("#### JVMTIagent: turned stress level 2 on ####\n"); + stress_lev = 2; + } + if ((strcmp(buf, "stress3")) == 0) { + if (debug_mode > 0) + printf("#### JVMTIagent: turned stress level 3 on ####\n"); + stress_lev = 3; + } + } +} + +static void getVerdict(JNIEnv *jni_env, const char *evnt) { + char error_msg[80]; + + if (vm_death_occured == TRUE) { + sprintf(error_msg, "JVMTIagent: getVerdict: %s event occured after VMDeath", + evnt); + + if (jni_env==NULL) { /* some event callbacks have no pointer to jni */ + printf("ERROR: %s\n", error_msg); + exit(97); + } + else + NSK_CPP_STUB2(FatalError, jni_env, error_msg); + } +} + +static void display(int level, const char format[], ...) { + va_list ar; + + if (debug_mode > level) { + va_start(ar, format); + vprintf(format, ar); + va_end(ar); + } +} + +/* agent procedure */ +static void JNICALL +agentProc(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) { +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + /* create JVMTI environment */ + if (!NSK_VERIFY((jvmti = + nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) + return JNI_ERR; + + doSetup(options); + + if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor, + jvmti, "_event_lock", &eventLock))) + return JNI_ERR; + + if (enableEventsCaps() == 0 && addStressEvents() == 0) { + display(0, "#### JVMTIagent: all events were successfully enabled and capabilities/events callbacks set ####\n\n"); + } else { + printf("ERROR(%s,%d): JVMTIagent terminated abnormally! ####\n", + __FILE__,__LINE__); + return JNI_ERR; + } + + /* register agent proc and arg */ + if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) + return JNI_ERR; + + return JNI_OK; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java b/test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java new file mode 100644 index 00000000000..f6a0b087334 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import nsk.share.*; + +import java.io.*; + +/** + * Wrapper for local process. + *

      + * This class provides abilities to launch such process, + * redirect standard output streams, wait for process terminates + * or kill the process, and so on. + *

      + * This object is finalized with nsk.share.Finalizer. + * + * @see nsk.share.FinalizableObject + * @see nsk.share.Finalizer + */ + +public class LocalProcess extends FinalizableObject { + + public final static int PROCESS_IS_ALIVE = 222; + + private Process process; + + protected Process getProcess() { + return process; + } + + public void launch (String[] args) throws IOException { + System.out.println("Launching process by array of args: "); + for (int mm=0; mm < args.length; mm++) { + System.out.println(" args[" + Integer.toString(mm) + "]: >" + + args[mm] + "<"); + + } + + process = Runtime.getRuntime().exec(args); + + Finalizer finalizer = new Finalizer(this); + finalizer.activate(); + } + + public void launch (String cmdLine) throws IOException { + System.out.println("Launching process by command line: " + cmdLine); + + process = Runtime.getRuntime().exec(cmdLine); + + Finalizer finalizer = new Finalizer(this); + finalizer.activate(); + } + + /** Return exit status. */ + public int getStatus () { + return process.exitValue(); + } + + /** Check whether the process has been terminated. */ + public boolean terminated() { + try { + int value = process.exitValue(); + return true; + } catch (IllegalThreadStateException e) { + return false; + } + } + + /** Wait until the process shutdown or crash. */ + public int waitFor () throws InterruptedException { + return process.waitFor(); + } + + /** + * Wait until the process shutdown or crash for given timeout in milliseconds. + * Returns LocalProcess.PROCESS_IS_ALIVE if process is not terminated + * after timeout. + */ + + public int waitFor (long timeMillisec) throws InterruptedException { + final Object waitObject = new Object(); + + class Watcher extends Thread { + int exitCode = LocalProcess.PROCESS_IS_ALIVE; + Process process; + + Watcher (Process process) { + this.process = process; + } + + public void run () { + try { + synchronized (this) { + exitCode = process.waitFor(); + } + } catch (InterruptedException ie) { + } + synchronized (waitObject) { + waitObject.notifyAll(); + } + } + + synchronized public int getExitCode() { + return exitCode; + } + } + + Watcher watcher; + // yield control to watcher for timeMillisec time. + synchronized (waitObject) { + watcher = new Watcher(process); + watcher.start(); + + waitObject.wait(timeMillisec); + } + + if (watcher.isAlive()) { + watcher.interrupt(); + } + + return watcher.getExitCode(); + } + + // --------------------------------------------------- // + + /** Get a pipe to write to the process' stdin stream. */ + public OutputStream getStdin () { + return process.getOutputStream(); + } + + /** Get a pipe to read the process' stdout stream. */ + public InputStream getStdout () { + return process.getInputStream(); + } + + /** Get a pipe to read the process stderr stream. */ + public InputStream getStderr () { + return process.getErrorStream(); + } + + /** Kill the process. */ + protected void kill() { + process.destroy(); + } + + /** + * Finalize mirror by invoking close(). + * + * @throws Throwable if any throwable exception is thrown during finalization + */ + protected void finalize() throws Throwable { + kill(); + super.finalize(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java new file mode 100644 index 00000000000..4a260fc3dd9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -0,0 +1,736 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; +import java.util.Vector; + +import nsk.share.test.LazyFormatString; + +/** + * This class helps to print test-execution trace messages + * and filter them when execution mode is not verbose. + *

      + * Verbose mode if defined by providing -verbose command line + * option, handled by ArgumentParser. Use verbose() + * method to determine which mode is used. + *

      + * Log provides with two main methods to print messages: + *

        + *
      • complain(String) - to print error message + *
      • display(String) - to print additional log message + *
      + * No other way to print messages to the log stream should be used. + *

      + * Error messages appeares in log stream in all modes. Additional log massages, + * printed with display() method will be filtered out, if log mode + * is not verbose. In verbose log made messages of both types are printed. + * Additionally, in verbose mode a summary of all occured errors will be printed + * at the program exit, by automatically invoking method + * printErrorsSummary(). + *

      + * To provide printing messages from different sources into one log + * with distinct prefixes use internal Log.Logger class. + * + * @see #verbose() + * @see #complain(String) + * @see #display(String) + * @see ArgumentParser + * @see Log.Logger + */ +public class Log extends FinalizableObject { + /** + * Report step-by-step activity to this stream. + * + * @deprecated Tests should not use this field directly. + */ + protected PrintStream out = null; + + /** + * Is log-mode verbose? + * Default value is false. + */ + private boolean verbose = false; + + /** + * Should log messages prefixed with timestamps? + * Default value is false. + */ + private boolean timestamp = false; + + /** + * Names for trace levels + */ + public static final class TraceLevel { + public static final int TRACE_NONE = 0; + public static final int TRACE_IMPORTANT = 1; + public static final int TRACE_NORMAL = 2; + public static final int TRACE_VERBOSE = 3; + public static final int TRACE_DEBUG = 4; + + public static final int DEFAULT = TRACE_IMPORTANT; + + public static final Map NAME_TO_LEVEL_MAP = new HashMap(); + static { + NAME_TO_LEVEL_MAP.put("none", TRACE_NONE); + NAME_TO_LEVEL_MAP.put("important", TRACE_IMPORTANT); + NAME_TO_LEVEL_MAP.put("info", TRACE_NORMAL); + NAME_TO_LEVEL_MAP.put("verbose", TRACE_VERBOSE); + NAME_TO_LEVEL_MAP.put("debug", TRACE_DEBUG); + NAME_TO_LEVEL_MAP.put("default", DEFAULT); + } + + public static int nameToLevel(String value) throws IllegalArgumentException { + Integer level = NAME_TO_LEVEL_MAP.get(value.toLowerCase()); + if ( level == null ) + throw new IllegalArgumentException("Wrong trace level: " + value); + + return level; + } + + public static String getLevelsString() { + StringBuffer result = new StringBuffer(); + for ( String s : NAME_TO_LEVEL_MAP.keySet() ) { + result.append(s).append(", "); + } + return result.substring(0, result.length() - 3); + } + } + + /** + * Threshold value for printing trace messages for debugging purpose. + * Default value is 0 a.k.a. TraceLevel.INFO; + */ + private int traceLevel = TraceLevel.DEFAULT; + + /** + * Is printing errors summary enabled? Default value is true; + */ + private boolean errorsSummaryEnabled = true; + + /** + * Is printing saved verbose messages on error enabled? Default value is true; + */ + private boolean verboseOnErrorEnabled = true; + + /** + * This errosBuffer will keep all messages printed via + * complain() method for final summary output. + * Ensure that buffer has enough room for messages to keep, + * to minimize probability or OutOfMemory error while keeping + * an error message in stress tests. + */ + private Vector errorsBuffer = new Vector(1000); + + /** + * Most tests in nsk do not log exceptions, they only log an error message. + * This makes failure analysis harder. + * To solve this we will automatically generate Exceptions for error logs. + * To not log too many Exceptions, we try to log each unique error only once. + * loggedExceptions contains all messages that have already been logged. + */ + private Set loggedExceptions = new HashSet(); + + /** + * This logBuffer will keep all messages printed via + * display() method in non-verbose mode until + * swithching verbose mode on or invoking complain(). + * Ensure that buffer has enough room for messages to keep, + * to minimize probability or OutOfMemory error while keeping + * an error message in stress tests. + */ + private Vector logBuffer = new Vector(1000); + + /** + * Did I already warned if output stream is not assigned? + */ + private boolean noOutWarned = false; + + ///////////////////////////////////////////////////////////////// + + /** + * Create new Log's only with Log(out) or with + * Log(out,argsHandler) constructors. + * + * @deprecated Extending test class with Log is obsolete. + */ + protected Log() { + // install finalizer to print errors summary at exit + Finalizer finalizer = new Finalizer(this); + finalizer.activate(); + + // Don't log exceptions from this method. It would just add unnecessary logs. + loggedExceptions.add("nsk.share.jdi.SerialExecutionDebugger.executeTests"); + } + + /** + * Incarnate new Log for the given stream and + * for non-verbose mode. + */ + public Log(PrintStream stream) { + this(); + out = stream; + } + + /** + * Incarnate new Log for the given stream; and + * either for verbose or for non-verbose mode accordingly to + * the given verbose key. + */ + public Log(PrintStream stream, boolean verbose) { + this(stream); + this.verbose = verbose; + } + + /** + * Incarnate new Log for the given stream; and + * either for verbose or for non-verbose mode accordingly to + * the given argsHandler. + */ + public Log(PrintStream stream, ArgumentParser argsParser) { + this(stream, argsParser.verbose()); + traceLevel = argsParser.getTraceLevel(); + timestamp = argsParser.isTimestamp(); + } + + ///////////////////////////////////////////////////////////////// + + /** + * Return true if log mode is verbose. + */ + public boolean verbose() { + return verbose; + } + + /** + * Return true if printing errors summary at exit is enabled. + */ + public boolean isErrorsSummaryEnabled() { + return errorsSummaryEnabled; + } + + /** + * Enable or disable printing errors summary at exit. + */ + public void enableErrorsSummary(boolean enable) { + errorsSummaryEnabled = enable; + } + + /** + * Return true if printing saved verbose messages on error is enabled. + */ + public boolean isVerboseOnErrorEnabled() { + return errorsSummaryEnabled; + } + + /** + * Enable or disable printing saved verbose messages on error. + */ + public void enableVerboseOnError(boolean enable) { + verboseOnErrorEnabled = enable; + } + + /** + * Enable or disable verbose mode for printing messages. + */ + public void enableVerbose(boolean enable) { + if (!verbose) { + flushLogBuffer(); + } + verbose = enable; + } + + public int getTraceLevel() { + return traceLevel; + } + + /** + * Set threshold for printing trace messages. + * Warning: trace level changes may NOT be observed by other threads immediately. + */ + public void setTraceLevel(int level) { + traceLevel = level; + } + + /** + * Return output stream of this Log object. + */ + public PrintStream getOutStream() { + return out; + } + + /** + * Returns a string that contains prefix concatenated + * with Throwable.printStackTrace() output. + */ + public static String printExceptionToString(Object prefix, Throwable exception) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(bos); + pw.println(prefix); + exception.printStackTrace(pw); + pw.close(); + return bos.toString(); + } + + /** + * Print message to the assigned output stream. + * + * @deprecated Test ought to be quiet if log mode is non-verbose + * and there is no errors found by the test. Methods + * display() and complain() + * are enough for testing purposes. + */ + public synchronized void println(String message) { + doPrint(message); + if (!verbose() && isVerboseOnErrorEnabled()) { + keepLog(composeLine(message)); + } + } + + /** + * Print message to the assigned output stream, + * if log mode is non-verbose. + * + * @deprecated Test ought to be quiet if log mode is non-verbose + * and there is no errors found by the test. Methods + * display() and complain() + * are enough for testing purposes. + */ + public synchronized void comment(String message) { + if (!verbose()) { + doPrint(message); + } + } + + /** + * Print trace message to the assigned output stream, + * only if specified level is less or equal for the + * trace level specified in command line by -trace.level + * option. + */ + public void trace(int level, Object message) { + if (level <= traceLevel) { + synchronized ( this ) { + doPrint("### TRACE " + level + ": " + message); + } + } + } + /** + * Print trace message and exception to + * the assigned output stream, + * only if specified level is less or equal for the + * trace level specified in command line by -trace.level + * option. + */ + public void trace(int level, Object message, Throwable exception) { + if (level <= traceLevel) { + trace(level, printExceptionToString(message, exception)); + } + } + + /** + * Print message to the assigned output stream, + * if log mode is verbose. The message will be lost, + * if execution mode is non-verbose, and there is no error messages + * printed. + */ + public synchronized void display(Object message) { + if (verbose()) { + doPrint(message.toString()); + } else if (isVerboseOnErrorEnabled()) { + keepLog(composeLine(message.toString())); + } else { + // ignore + } + } + + /** + * Print error message to the assigned output stream + * (or to stderr if output is not specified) and keep the message + * into errorsBuffer. + */ + public synchronized void complain(Object message) { + if (!verbose() && isVerboseOnErrorEnabled()) { + PrintStream stream = findOutStream(); + stream.println("#> "); + stream.println("#> WARNING: switching log to verbose mode,"); + stream.println("#> because error is complained"); + stream.println("#> "); + stream.flush(); + enableVerbose(true); + } + String msgStr = message.toString(); + printError(msgStr); + if (isErrorsSummaryEnabled()) { + keepError(msgStr); + } + + logExceptionForFailureAnalysis(msgStr); + } + + /** + * Print error message and exception + * to the assigned output stream + * (or to stderr if output is not specified) and keep the message + * into errorsBuffer. + */ + public void complain(Object message, Throwable exception) { + if ( exception != null ) + complain(printExceptionToString(message, exception)); + else + complain(message); + } + + /** + * Create an Exception and print the stack trace for an error msg. + * This makes it possible to detect a failure reason for this error. + */ + private void logExceptionForFailureAnalysis(String msg) { + // Some error messages are formatted in multiple lines and with tabs. + // We clean the messages to help parse the stack traces for failure analysis. + // We keep at most 2 lines, otherwise the error message may be too long. + String[] lines = msg.split("[\r\n]+"); + msg = lines.length >= 2 ? lines[0] + " " + lines[1] : lines[0]; + msg = msg.replaceAll("\t", " "); + + // Create a dummy exception just so we can print the stack trace. + TestFailure e = new TestFailure(msg); + StackTraceElement[] elements = e.getStackTrace(); + + final int callerIndex = 2; // 0=this function, 1=complain(), 2=caller + if (elements.length <= callerIndex) { + return; + } + + // Only log the first complain message from each function. + // The reason is that some functions splits an error message + // into multiple lines and call complain() many times. + // We do not want a RULE for each of those calls. + // This means that we may miss some rules, but that + // is better than to create far too many rules. + String callerClass = elements[callerIndex].getClassName(); + String callerMethod = elements[callerIndex].getMethodName(); + String callerKey = callerClass + "." + callerMethod; + boolean isAlreadyLogged = loggedExceptions.contains(msg) || loggedExceptions.contains(callerKey); + + if (!isAlreadyLogged) { + PrintStream stream = findOutStream(); + stream.println("The following stacktrace is for failure analysis."); + e.printStackTrace(stream); + } + + loggedExceptions.add(callerKey); + loggedExceptions.add(msg); + } + + ///////////////////////////////////////////////////////////////// + + /** + * Redirect log to the given stream, and switch + * log mode to verbose. + * Prints errors summary to current stream, cancel current stream + * and switches to new stream. Turns on verbose mode for new stream. + * + * @deprecated This method is obsolete. + */ + protected synchronized void logTo(PrintStream stream) { + finalize(); // flush older log stream + out = stream; + verbose = true; + } + + ///////////////////////////////////////////////////////////////// + + /** + * Print all messages from log buffer which were hidden because + * of non-verbose mode, + */ + private synchronized void flushLogBuffer() { + if (!logBuffer.isEmpty()) { + PrintStream stream = findOutStream(); + for (int i = 0; i < logBuffer.size(); i++) { + stream.println(logBuffer.elementAt(i)); + } + stream.flush(); + } + } + + /** + * Return out stream if defined or Sytem.err otherwise; + * print a warning message when System.err is used first time. + */ + private synchronized PrintStream findOutStream() { + PrintStream stream = out; + if (stream == null) { + stream = System.err; + if (!noOutWarned) { + noOutWarned = true; + stream.println("#> "); + stream.println("#> WARNING: switching log stream to stderr,"); + stream.println("#> because no output stream is assigned"); + stream.println("#> "); + }; + }; + stream.flush(); + return stream; + } + + /** + * Compose line to print possible prefixing it with timestamp. + */ + private String composeLine(String message) { + if (timestamp) { + long time = System.currentTimeMillis(); + long ms = time % 1000; + time /= 1000; + long secs = time % 60; + time /= 60; + long mins = time % 60; + time /= 60; + long hours = time % 24; + return "[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message; + } + return message; + } + + /** + * Print the given message either to out + * stream, or to System.err if out + * stream is not specified. + */ + private synchronized void doPrint(String message) { + PrintStream stream = findOutStream(); + stream.println(composeLine(message)); + stream.flush(); + } + + /** + * Print the given error message either to out + * stream, or to System.err if out + * stream is not specified. + */ + private synchronized void printError(String message) { + // Print each line with the ERROR prefix: + BufferedReader br = new BufferedReader(new StringReader(message)); + for (String line; ; ) { + try { + line = br.readLine(); + if (line == null) + break; + doPrint("# ERROR: " + line); + } catch (IOException e) { + throw new TestBug("Exception in Log.printError(): " + e); + }; + } + } + + /** + * Keep the given log message into logBuffer. + */ + private synchronized void keepLog(String message) { + logBuffer.addElement(message); + } + + /** + * Keep the given error message into errorsBuffer. + */ + private synchronized void keepError(String message) { + errorsBuffer.addElement(message); + } + + /** + * Print errors messages summary from errors buffer if any; + * print a warning message first. + */ + private synchronized void printErrorsSummary() { + if (errorsBuffer.size() <= 0) + return; + + PrintStream stream = findOutStream(); + stream.println(); + stream.println(); + stream.println("#> "); + stream.println("#> SUMMARY: Following errors occured"); + stream.println("#> during test execution:"); + stream.println("#> "); + stream.flush(); + + for (Enumeration e = errorsBuffer.elements(); e.hasMoreElements(); ) { + printError((String) e.nextElement()); + } + } + + /** + * Print errors summary if mode is verbose, flush and cancel output stream. + */ + protected void finalize() { + if (verbose() && isErrorsSummaryEnabled()) { + printErrorsSummary(); + } + if (out != null) + out.flush(); + out = null; + } + + /** + * Perform finalization at the exit. + */ + public void finalizeAtExit() { + finalize(); + } + + /** + * This class can be used as a base for each class that use Log + * for print messages and errors. + * Logger provides with ability to print such messages with + * specified prefix to make it possible to distinct messages printed from + * different sources. + * + * @see Log + */ + public static class Logger { + + /** + * Default prefix for messages. + */ + public static final String LOG_PREFIX = ""; + + /** + * Log to print messages to. + */ + protected Log log = null; + + /** + * Prefix for messages. + */ + protected String logPrefix = LOG_PREFIX; + + /** + * Make Logger object with empty Log and + * default prefix. + * This method may be used only in derived class, that should specify + * the used Log object further and assign it to log. + * + * @see #log + * @see #setLogPrefix + */ + protected Logger() { + } + + /** + * Make Logger object for specified Log + * with default prefix. + * + * @see #setLogPrefix + */ + public Logger(Log log) { + this.log = log; + } + + /** + * Make Logger object for specified Log with + * given messages prefix. + */ + public Logger(Log log, String prefix) { + this.log = log; + this.logPrefix = prefix; + } + + /** + * Return Log object. + */ + public Log getLog() { + return log; + } + + /** + * Return output stream of this Log object. + */ + public PrintStream getOutStream() { + return log.getOutStream(); + } + + /** + * Set prefix for printed messages. + */ + public void setLogPrefix(String prefix) { + logPrefix = prefix; + } + + /** + * Make printable message by adding logPrefix to it. + */ + public String makeLogMessage(String message) { + return logPrefix + message; + } + + /** + * Print trace message by invoking Log.trace(). + * + * @see Log#trace + */ + public void trace(int level, String message) { + log.trace(level, makeLogMessage(message)); + } + + /** + * Print message by invoking Log.println(). + * + * @see Log#println + */ + public void println(String message) { + log.println(makeLogMessage(message)); + } + + /** + * Print message by invoking Log.display(). + * + * @see Log#display + */ + public void display(String message) { + log.display(makeLogMessage(message)); + } + + /** + * Complain about an error by invoking Log.complain() method. + * + * @see Log#complain + */ + public void complain(String message) { + log.complain(makeLogMessage(message)); + } + + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java new file mode 100644 index 00000000000..4fb0db7675d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +public class NativeUtils { + static { + System.loadLibrary("native_utils"); + } + + public static native long getCurrentPID(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ObjectInstancesManager.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ObjectInstancesManager.java new file mode 100644 index 00000000000..502e962a87b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ObjectInstancesManager.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +import java.util.*; + +/* + * Class create/delete instances with given reference type and given referrers number + */ +public class ObjectInstancesManager +{ + public static String STRONG_REFERENCE = "STRONG"; + public static String WEAK_REFERENCE = "WEAK"; + public static String SOFT_REFERENCE = "SOFT"; + public static String PHANTOM_REFERENCE = "PHANTOM"; + public static String JNI_GLOBAL_REFERENCE = "JNI_GLOBAL"; + public static String JNI_LOCAL_REFERENCE = "JNI_LOCAL"; + public static String JNI_WEAK_REFERENCE = "JNI_WEAK"; + + // used to create references of all types + private static String USE_ALL_REFERENCE_TYPES = "ALL_REFERENCE_TYPES"; + + private Map> instances = new TreeMap>(); + + public static Set primitiveArrayClassNames = new HashSet(); + + static + { + primitiveArrayClassNames.add("boolean[]"); + primitiveArrayClassNames.add("byte[]"); + primitiveArrayClassNames.add("char[]"); + primitiveArrayClassNames.add("int[]"); + primitiveArrayClassNames.add("long[]"); + primitiveArrayClassNames.add("float[]"); + primitiveArrayClassNames.add("double[]"); + } + + + public static Set allReferenceTypes = new HashSet(); + + static + { + allReferenceTypes.add(ObjectInstancesManager.STRONG_REFERENCE); + allReferenceTypes.add(ObjectInstancesManager.WEAK_REFERENCE); + allReferenceTypes.add(ObjectInstancesManager.SOFT_REFERENCE); + allReferenceTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE); + allReferenceTypes.add(ObjectInstancesManager.JNI_GLOBAL_REFERENCE); + allReferenceTypes.add(ObjectInstancesManager.JNI_LOCAL_REFERENCE); + allReferenceTypes.add(ObjectInstancesManager.JNI_WEAK_REFERENCE); + } + + public static boolean isWeak(String type) { + return !(type.equals(ObjectInstancesManager.JNI_GLOBAL_REFERENCE) + || type.equals(ObjectInstancesManager.JNI_LOCAL_REFERENCE) + || type.equals(ObjectInstancesManager.STRONG_REFERENCE)); + + } + + public static Log log; + + public ObjectInstancesManager(Log log) + { + ObjectInstancesManager.log = log; + } + + // delete a given number of referrers + public void deleteReferrers(String className, int referrersCount, Set referrerTypes) + { + Collection objectInstances; + + objectInstances = instances.get(className); + + if(objectInstances == null) + { + log.display("Error command 'deleteObjectInstances' is requsted: instances of class " + className + " was not created"); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + return; + } + + Iterator iterator = objectInstances.iterator(); + + while(iterator.hasNext()) + { + ReferringObjectSet debugeeObjectReference = iterator.next(); + if (referrerTypes.isEmpty() || referrerTypes.contains(debugeeObjectReference.getReferenceType())) { + debugeeObjectReference.delete(referrersCount); + + if(debugeeObjectReference.getReferrerCount() == 0) + iterator.remove(); + } + } + } + + // delete all object referrers, it is equal to make object unreacheable + public void deleteAllReferrers(int count, String className) + { + Collection objectInstances; + + objectInstances = instances.get(className); + + if(objectInstances == null) + { + throw new TestBug("Command 'deleteObjectInstances' is requsted: instances of class " + className + " was not created"); + } + + Iterator iterator = objectInstances.iterator(); + + if(count == 0) + count = objectInstances.size(); + + for(int i = 0; i < count; i++) + { + ReferringObjectSet debugeeObjectReference = iterator.next(); + debugeeObjectReference.deleteAll(); + + iterator.remove(); + } + } + + // create object instance with referrers of all possible types + public void createAllTypeReferences(String className, int count) + { + createReferences(count, className, 1, allReferenceTypes); + } + + // create a given number of object instances with given number of referrers + public void createReferences(int count, String className, int referrerCount, Set referrerTypes) + { + Collection objectInstances; + + Class klass = null; + + if(!primitiveArrayClassNames.contains(className)) + { + try + { + klass = Class.forName(className); + } + catch(ClassNotFoundException e) + { + log.display("Can't find class: " + className); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + return; + } + } + + objectInstances = instances.get(className); + + if(objectInstances == null) + { + objectInstances = new ArrayList(); + instances.put(className, objectInstances); + } + + for(int i = 0; i < count; i++) + { + try + { + Object instance; + + if(!primitiveArrayClassNames.contains(className)) + { + instance = klass.newInstance(); + } + else + { + instance = createPrimitiveTypeArray(className); + } + + for(String type : referrerTypes) { + objectInstances.add(new ReferringObjectSet(instance, referrerCount, type)); + } + } + catch(Exception e) + { + log.display("Unexpected exception: " + e); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + } + + public Object createPrimitiveTypeArray(String typeName) + { + int arraySize = 1; + + if(typeName.equals("boolean[]")) + return new boolean[arraySize]; + else + if(typeName.equals("byte[]")) + return new byte[arraySize]; + else + if(typeName.equals("char[]")) + return new char[arraySize]; + else + if(typeName.equals("int[]")) + return new int[arraySize]; + else + if(typeName.equals("long[]")) + return new long[arraySize]; + else + if(typeName.equals("float[]")) + return new float[arraySize]; + else + if(typeName.equals("double[]")) + return new double[arraySize]; + else + { + throw new TestBug("Invalid primitive type array type name: " + typeName); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Oddity.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Oddity.java new file mode 100644 index 00000000000..23520278a19 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Oddity.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * Oddity exception is used to simulate C/C++ style assert() + * facility. It is thrown when an internal contradiction is revealed, which + * may do not indicate a bug in the JDI implementation or in the test. + */ +public class Oddity extends Failure { + /** Explain particular oddity. */ + public Oddity (String message) { + super(message); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Pair.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Pair.java new file mode 100644 index 00000000000..8c7d54b37d9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Pair.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +public class Pair { + final public A first; + final public B second; + + private Pair(A first, B second) { + this.first = first; + this.second = second; + } + + public static Pair of(A first, B second) { + return new Pair(first, second); + } + + @Override + public String toString() { + return "(" + first + ", " + second + ")"; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Paragrep.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Paragrep.java new file mode 100644 index 00000000000..243de6c022a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Paragrep.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.*; +import java.util.regex.*; + +/** + * Weak emulator of perl's grep function with very small functionality. + * This class does not use java.util.regexp classes which appear in + * JDK1.4 API. + * + * @see Grep + */ + +public class Paragrep { + + String[] stringArray; + /** + * Takes String array as character sequence for matching the pattern. + */ + public Paragrep (String[] stringArray) { + this.stringArray = stringArray; + } + + /** + * Returns number of non-interleaved occurences of the pattern string. + */ + public int find (String pattern) { + if (pattern.length() == 0) { + throw new Failure("Empty string as input parameter for Grep.find(pattern) method"); + } + int counter = 0; + for (int i = 0; i < stringArray.length; i++) { + + String string = stringArray[i]; + if (string != null) { + // Find all non-interleaved occurences of pattern in this string + for (int ind = 0; ind < string.length(); ) { + int k = 0; + if ((k = string.indexOf(pattern, ind)) >= 0) { + counter++; + ind = k + pattern.length(); + } else { + break; + } + } + } + } + return counter; + } + + /** + * Returns all string in stringArray which have + * occurences of the pattern string. + */ + public String[] findStrings (String pattern) { + if (pattern.length() == 0) { + throw new Failure("Empty string as input parameter for Grep.find(pattern) method"); + } + Vector v = new Vector(); + for (int i = 0; i < stringArray.length; i++) { + String string = stringArray[i]; + if (string != null && string.indexOf(pattern) >= 0) { + v.add(string); + } + } + String[] result = new String[v.size()]; + v.toArray(result); + return result; + } + + /** + * Returns first string of stringArray which contains + * the pattern string or empty string othrewise. + */ + public String findFirst (String pattern) { + if (pattern.length() == 0) { + throw new Failure("Empty string as input parameter for Paragrep.findFirst(pattern) method"); + } + String result = ""; + for (int i = 0; i < stringArray.length; i++) { + String string = stringArray[i]; + if (string != null) { + if (string.indexOf(pattern) >= 0) { + result = string; + break; + } + } + } + return result; + } + + /** + * Returns first string of stringArray which contains + * all of the pattern strings or empty string otherwise. + */ + public String findFirst (Vector patternVector) { + if (patternVector.isEmpty()) { + throw new Failure("Empty vector as input parameter for Paragrep.findFirst(patternVector) method"); + } + String[] patterns = new String[patternVector.size()]; + patternVector.toArray(patterns); + String result = ""; + for (int i = 0; i < stringArray.length; i++) { + String string = stringArray[i]; + if (string != null && string.length() > 0) { + for (int j = 0; j < patterns.length; j++) { + String pattern = patterns[j]; + if (string.indexOf(pattern) >= 0) { + if (j + 1 == patterns.length) { + // found all patterns in the current string + result = string; + i = stringArray.length; + } + } else { + break; + } + } + } + } + return result; + } + + /** + * Returns count of strings in stringArray which contain + * all of the pattern strings. + */ + public int find (Vector patternVector) { + if (patternVector.isEmpty()) { + throw new Failure("Empty vector as input parameter for Paragrep.find(patternVector) method"); + } + String[] patterns = new String[patternVector.size()]; + patternVector.toArray(patterns); + int counter = 0; + + for (int i = 0; i < stringArray.length; i++) { + String string = stringArray[i]; + if (string != null && string.length() > 0) { + for (int j = 0; j < patterns.length; j++) { + String pattern = patterns[j]; + if (string.indexOf(pattern) >= 0) { + if (j + 1 == patterns.length) { + // found all patterns in the current string + counter++; + } + } else { + break; + } + } + } + } + return counter; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/PrintProperties.java b/test/hotspot/jtreg/vmTestbase/nsk/share/PrintProperties.java new file mode 100644 index 00000000000..609daefd0ab --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/PrintProperties.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.Properties; + +/** + * This program prints system properties. + */ +public class PrintProperties { + public static void main(String[] args) { + Properties pr = System.getProperties(); + switch (args.length) { + case 0: + pr.list(System.out); + System.exit(0); + case 1: + String value = pr.getProperty(args[0]); + if (value == null) { + System.err.println("Not found"); + System.exit(1); + } else { + System.out.println(value); + System.exit(0); + } + default: + System.out.println("Usage:"); + System.out.println(" PrintProperties"); + System.out.println(" PrintProperties "); + System.exit(255); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java b/test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java new file mode 100644 index 00000000000..f78f82b11f1 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.*; +import java.lang.reflect.Method; +import java.util.*; + +/** + * Class used as an agent for Java serviceability reliability testing (RAS). + * It sets different RAS options and/or modes for a special agent which + * actually performs the specified RAS testing.
      + * The agent recognizes arguments, started with ''-ras.''. They + * may be as follows:

      + *

    • -ras.help - print usage message and exit + *
    • -ras.verbose - verbose mode + *
    • -ras.invoke_run - invoke the method run(String[],PrintStream) + * of the test instead of main(String[]) which is invoked by default. + *
    • -ras.hotswap=<stress_level> - enable JVMTI hotswap of + * the currently running test classes. Here are the possible HotSwap stress + * levels:
      + * 0 - HotSwap off
      + * 2 - HotSwap tested class in every JVMTI method entry event of running test + * (default mode)
      + * 20 - HotSwap tested class in every JVMTI method entry event of every class
      + * 3 - HotSwap tested class in every JVMTI single step event of running test
      + * 4 - HotSwap tested class in every JVMTI exception event of running test
      + * 40 - HotSwap tested class in every JVMTI exception event of every class

      + */ +public class RASagent { + static final int HOTSWAP_OFF = 0; + static final int HOTSWAP_EVERY_METHOD_ENTRY = 2; + static final int HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS = 20; + static final int HOTSWAP_EVERY_SINGLE_STEP = 3; + static final int HOTSWAP_EVERY_EXCEPTION = 4; + static final int HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS = 40; + + // path to the directory with class files of the invoked test + static String clfBasePath = null; + + private static boolean verbose = false; + + private static PrintStream out; + + native static int setHotSwapMode(boolean vrb, int stress_lev, + String shortName); + + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new RASagent().runThis(argv, out); + } + + private int runThis(String argv[], PrintStream out) { + int skipArgs = 1; // number of arguments which must be skipped + // for the invoked test + boolean invokeRun = false; // invoke the method "main" by default + int hotSwapMode = HOTSWAP_EVERY_METHOD_ENTRY; // HotSwap default stress level + int res; + String hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY"; + + RASagent.out = out; + + if (argv.length != 0) { + // parse arguments for the RASagent and then skip them + while(argv[skipArgs-1].startsWith("-ras.")) { + if (argv[skipArgs-1].equals("-ras.verbose")) { + verbose = true; + } else if (argv[skipArgs-1].equals("-ras.help")) { + printHelp(); + return Consts.TEST_FAILED; + } else if (argv[skipArgs-1].equals("-ras.invoke_run")) { + invokeRun = true; + } else if (argv[skipArgs-1].startsWith("-ras.hotswap=")) { + try { + hotSwapMode = Integer.parseInt( + argv[skipArgs-1].substring(argv[skipArgs-1].lastIndexOf("=")+1)); + } catch (NumberFormatException e) { + e.printStackTrace(); + out.println("\nERROR: RASagent: specified HotSwap mode \"" + + hotSwapMode + "\" is not an integer"); + printHelp(); + return Consts.TEST_FAILED; + } + switch(hotSwapMode) { + case HOTSWAP_EVERY_METHOD_ENTRY: + hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY"; + break; + case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS: + hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS"; + break; + case HOTSWAP_EVERY_SINGLE_STEP: + hotSwapModeName = "HOTSWAP_EVERY_SINGLE_STEP"; + break; + case HOTSWAP_EVERY_EXCEPTION: + hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION"; + break; + case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS: + hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS"; + break; + default: + out.println("\nERROR: RASagent: specified HotSwap mode \"" + + hotSwapMode + "\" is unrecognized"); + printHelp(); + return Consts.TEST_FAILED; + } + } + skipArgs++; + } + + String shortTestName = getTestNameAndPath(argv[skipArgs-1]); + + display("\n#### RASagent: setting hotswap mode \"" + + hotSwapModeName + "\" for class \"" + + shortTestName + "\" ..."); + if ((res = setHotSwapMode(verbose, hotSwapMode, shortTestName)) != 0) { + out.println("\nERROR: RASagent: unable to set HotSwap stress level for \"" + + shortTestName + "\", exiting"); + return Consts.TEST_FAILED; + } + display("\n#### RASagent: ... setting hotswap mode done"); + + try { + Class testCls = Class.forName(argv[skipArgs-1]); + display("\n#### RASagent: main class \"" + + testCls.toString() + "\" loaded"); + + // copy arguments for the invoked test + String args[] = new String[argv.length-skipArgs]; + System.arraycopy(argv, skipArgs, args, 0, args.length); + + // invoke the test + if (invokeRun) + return invokeRunMethod(testCls, args); + else + return invokeMainMethod(testCls, args); + } catch(ClassNotFoundException e) { + // just pass: the invoked test is already a RAS specific one + out.println("\nWARNING: the test was not really run due to the following error:" + + "\n\tunable to get the Class object for \"" + + argv[skipArgs-1] + "\"\n\tcaught: " + e); + return Consts.TEST_PASSED; + } + + } else { + out.println("\nERROR: RASagent: required test name is absent in parameters list"); + return Consts.TEST_FAILED; + } + } + + /** + * Verify that test's class file exists with a path given as a parameter + * and, if so, store that path in the static field "clfBasePath". + */ + private boolean pathValid(String pathToCheck, String testName) { + String fullPath = pathToCheck + File.separator + + testName.replace('.', File.separatorChar) + ".class"; + File classFile = null; + + display("\n#### RASagent: verifying class path\n\t" + + pathToCheck + " ..."); + try { + classFile = new File(fullPath); + } catch (NullPointerException e) { + e.printStackTrace(); + out.println("\nERROR: RASagent: verification of class file " + + fullPath + " failed: caught " + e); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + if (classFile.exists()) { + clfBasePath = pathToCheck; + display("\tthe class file exists:\n\t\t" + + fullPath + "\n\tclass file base directory found:\n" + + "\t\t" + clfBasePath + + "\n#### RASagent: ... class path verification done\n"); + return true; + } + else { + display("\tno class file at location :\n\t\t" + + fullPath + + "\n#### RASagent: ... class path verification done\n"); + return false; + } + } + + /** + * Get short name of an invoked test (i.e. without package name) and + * store path to the directory with the test's class files. + */ + private String getTestNameAndPath(String testName) { + String shortTestName = testName; + String packageName = ""; + + // if '.' occurs, it means that current test is inside a package + if (testName.lastIndexOf(".") != -1) { + shortTestName = testName.substring(testName.lastIndexOf(".")+1); + packageName = testName.substring(0, testName.lastIndexOf(".")); + } + + StringTokenizer clPathes = new StringTokenizer( + System.getProperty("java.class.path"), File.pathSeparator); + + while(clPathes.hasMoreTokens()) { + String clPath = clPathes.nextToken(); + + // trying to load a class file defining the current test from + // this entry of "java.class.path": the class file may locate + // at the test's work directory or if it's already compiled, + // at any directory in classpath + if (pathValid(clPath, testName)) + return shortTestName; + } + + // directory with the test's class files was not found. + // Actually, it means that the invoked test has own Java + // options such as, for example, "-verify" + out.println("\nWARNING: the test was not really run due to the following reason:" + + "\n\tthe invoked test has the own Java option: " + + testName); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED); + + return null; // fake return for too smart javac + } + + /** + * Invoke the method main(String[]) of the test. + */ + private int invokeMainMethod(Class testCls, String args[]) { + Class[] methType = { String[].class }; + Object[] methArgs = { args }; + + return invokeMethod(testCls, "main", methType, methArgs); + } + + /** + * Invoke the method run(String[], PrintStream) of the test. + */ + private int invokeRunMethod(Class testCls, String args[]) { + Class[] methType = { String[].class, PrintStream.class }; + Object[] methArgs = { args, out }; + + return invokeMethod(testCls, "run", methType, methArgs); + } + + /** + * Low level invocation of the test. + */ + private int invokeMethod(Class testCls, String methodName, + Class methType[], Object methArgs[]) { + + try { + Method testMeth = testCls.getMethod(methodName, methType); + display("\n#### RASagent: invoking method \"" + + testMeth.toString() + "\" ..."); + + Object result = testMeth.invoke(null, methArgs); + + display("\n#### RASagent: ... invocation of \"" + + testMeth.toString() + "\" done"); + if (result instanceof Integer) { + Integer retCode = (Integer) result; + return retCode.intValue(); + } + } catch(NoSuchMethodException e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: unable to get method \"" + + methodName + "\" in class " + + testCls + "\n\tcaught " + e); + return Consts.TEST_FAILED; + } catch(Exception e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: caught during invokation of the test class " + + testCls + " " + e); + return Consts.TEST_FAILED; + } + + return -1; + } + + /** + * Load class bytes for HotSwap. + */ + static byte[] loadFromClassFile(String signature) { + String testPath = clfBasePath + File.separator + signature.substring( + 1, signature.length()-1).replace('/', File.separatorChar) + ".class"; + File classFile = null; + + display("\n#### RASagent: looking for class file\n\t" + + testPath + " ..."); + + try { + classFile = new File(testPath); + } catch (NullPointerException e) { + out.println("\nFAILURE: RASagent: path name to the redefining class file is null"); + } + + display("\n#### RASagent: loading " + classFile.length() + + " bytes from class file "+ testPath + " ..."); + byte[] buf = new byte[(int) classFile.length()]; + try { + InputStream in = new FileInputStream(classFile); + in.read(buf); + in.close(); + } catch(FileNotFoundException e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: loadFromClassFile: file " + + classFile.getName() + " not found"); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } catch (Exception e) { + e.printStackTrace(); + out.println("\nFAILURE: RASagent: unable to load bytes from the file:\n"); + out.println("\t" + testPath + ": caught " + e); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + display("\n#### RASagent: ... " + classFile.length() + " bytes loaded"); + + return buf; + } + + /** + * This method is used in verbose mode. It prints paramter string only + * in case of verbose mode. + */ + private static void display(String msg) { + if (verbose) + out.println(msg); + } + + /** + * This method prints out RASagent usage message. + */ + private static void printHelp() { + out.println("\nRASagent usage: RASagent [option, ...] test" + + "\n\t-ras.help print this message and exit" + + "\n\t-ras.verbose verbose mode (off by default)" + + "\n\t-ras.hotswap=mode enable HotSwap of the running test classes" + + "\n\t\twhere mode is:" + + "\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY + + " - hotswap tested class in its every method entry event" + + "\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS + + " - hotswap tested class in every method entry event for every class" + + "\n\t\t\t" + HOTSWAP_EVERY_SINGLE_STEP + + " - hotswap tested class in its every single step event" + + "\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION + + " - hotswap tested class in its every exception event" + + "\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS + + " - hotswap tested class in every exception event for every class\n" + + "\n\t-ras.invoke_run invoke the method run() of the test" + + "\n\t\tinstead of main() by default"); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/README b/test/hotspot/jtreg/vmTestbase/nsk/share/README new file mode 100644 index 00000000000..9da486350bd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/README @@ -0,0 +1,128 @@ +Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This code is free software; you can redistribute it and\\\/or modify it +under the terms of the GNU General Public License version 2 only, as +published by the Free Software Foundation. +This code is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. + +--------------------------------------------------------------------------------- + +This directory contains source files of NSK tests framework +shared between all NSK tests. + +Files located directly in this directory provide general support +for all tests. + +Files in the subdirectories provide specific support for tests of +particular subsuites. + +--------------------------------------------------------------------------------- + +Short description of files: + + common exceptions: + Failure,java, TestBug.java, Oddity.java + common constants: + Consts.java + parsing command line arguments: + ArgumentPareser.java + output of errors and messages: + Log.java + process running: + LocalProcess.java, IORedirector.java + class loading/unloading: + DummyClassLoader.java, ZipClassLoader.java, + CustomClassLoader.java, ClassUnloder.java + objects finalization: + Finalizable.java, FinalizableObject.java, Finalizer.java + threads synchronization: + Wicket.java + text processing: + Grep.java, Paragrep.java + timeouts handling: + Harakiri.java, TimeoutHandler.java + tree structures support: + Denotation.java, TreeNodesDenotation.java + RAS mode support: + RASagent.java, JVMTIagent.c + JVMDI tests support: + JVMDITools.h, JVMDITools.c + +Short description of subdirectories: + + Alien - support for accessing external tests (JCK) + native - support for native part of NSK tests + jni - support for JNI tests and accessing JNI API + jvmti - support for JVMTI tests and accessing JVMTI API + jpda - support for two-VMs JPDA tests + jdwp - support for JDWP tests and accessing JDWP API + jdi - support for JDI tests and accesing JDI API + jdb - support for JDB tests and accessing JDB tool + monitoring - support for monitoring tests and accessing Java Monitoring&Management API + sysdict - support for System Dictionary tests + gc - support for GC tests + regression - support for regression tests for known bugs + split_verifier - support for Split Verifier tests + +For more detailed description see README files in subdirectories. + +--------------------------------------------------------------------------------- + +Naming conventions + +Classes: + + All shared classes are groupped into packages to prevent + name collision. + + All classes exported directly from this directory are + of package: + + nsk.share + + All classes exported from subdirectories are of particular + subpackage, e.g.: + + nsk.share.jpda + nsk.share.jdwp + nsk.share.jdi + nsk.share.jdb + nsk.share.monitoring + nsk.share.sysdict + +Native functions and macroses: + + Most native functions have special prefix to prevent linking collisions. + Most macroses also have special prefix and are wrote in upper register. + + Here is typical naming scheme used for native functions and macroses: + + share/native + functions: nsk_* + macroses: NSK_* + + share/jni + functions: nsk_jni_* + macroses: NSK_JNI_* + + share/jvmti + functions: nsk_jvmti_* + macroses: NSK_JVMTI_* + + However, some native functions and macroses do not follow this scheme, + in order to preserve compatibility with old tests. + +--------------------------------------------------------------------------------- diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObject.java new file mode 100644 index 00000000000..1dd4bb9ffc1 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObject.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +/* + * This class create/delete reference with given type. + * + * Supported reference types are: + * - strong + * - soft + * - weak + * - phantom + * - jni local + * - jni global + * - jni weak + */ +public class ReferringObject +{ + static + { + System.loadLibrary("JNIreferences"); + } + + public final static int maxJNIGlobalReferences = 1000; + public final static int maxJNIWeakReferences = 1000; + + private Object reference; + + private String referenceType; + + //used for storing jni global and jni weak references + private int referenceIndex; + + public ReferringObject(Object object, String referenceType) + { + this.referenceType = referenceType; + + if(referenceType.equals(ObjectInstancesManager.STRONG_REFERENCE)) + { + createStrongReference(object); + } + else + if(referenceType.equals(ObjectInstancesManager.SOFT_REFERENCE)) + { + createSoftReference(object); + } + else + if(referenceType.equals(ObjectInstancesManager.WEAK_REFERENCE)) + { + createWeakReference(object); + } + else + if(referenceType.equals(ObjectInstancesManager.PHANTOM_REFERENCE)) + { + createPhantomReference(object); + } + else + if(referenceType.equals(ObjectInstancesManager.JNI_GLOBAL_REFERENCE)) + { + createJNIGlobalReference(object); + } + else + if(referenceType.equals(ObjectInstancesManager.JNI_LOCAL_REFERENCE)) + { + createJNILocalReference(object); + } + else + if(referenceType.equals(ObjectInstancesManager.JNI_WEAK_REFERENCE)) + { + createJNIWeakReference(object); + } + else + throw new IllegalArgumentException("Invalid reference type: " + referenceType); + } + + public void delete() + { + if(referenceType == null) + { + throw new TestBug("Reference type is null"); + } + + if(referenceType.equals(ObjectInstancesManager.SOFT_REFERENCE)) + { + if(reference == null) + { + throw new TestBug("Reference is null for SoftReference"); + } + + if(((SoftReference)reference).get() == null) + { + // throw new TestBug("Test execution error: SoftReference was collected"); + } + } + else + if(referenceType.equals(ObjectInstancesManager.WEAK_REFERENCE)) + { + if(reference == null) + { + throw new TestBug("Reference is null for WeakReference"); + } + + if(((WeakReference)reference).get() == null) + { + // throw new TestBug("Test execution error: WeakReference was collected"); + } + } + else + if(referenceType.equals(ObjectInstancesManager.PHANTOM_REFERENCE)) + { + if(reference == null) + { + throw new TestBug("Reference is null for PhantomReference"); + } + } + else + if(referenceType.equals(ObjectInstancesManager.JNI_GLOBAL_REFERENCE)) + { + deleteJNIGlobalReferenceNative(referenceIndex); + } + else + if(referenceType.equals(ObjectInstancesManager.JNI_LOCAL_REFERENCE)) + { + deleteJNILocalReference(); + } + else + if(referenceType.equals(ObjectInstancesManager.JNI_WEAK_REFERENCE)) + { + try { + deleteJNIWeakReferenceNative(referenceIndex); + } catch (Throwable t) + { + + } + } + + reference = null; + } + + private void createStrongReference(Object object) + { + reference = object; + } + + private void createSoftReference(Object object) + { + reference = new SoftReference(object); + } + + private void createWeakReference(Object object) + { + reference = new WeakReference(object); + } + + private void createPhantomReference(Object object) + { + reference = new PhantomReference(object, new ReferenceQueue()); + } + + private void createJNIGlobalReference(Object object) + { + referenceIndex = createJNIGlobalReferenceNative(object, maxJNIGlobalReferences); + + if(referenceIndex < 0) + { + throw new TestBug("Error on creation of JNI_Global reference, Possible number of JNI_Global references exceeded max available value!"); + } + } + + /* + * Since jni local reference valid only for duration of native method call, to create jni local reference + * special thread is created which enter in native method, create jni local reference and wait + */ + private void createJNILocalReference(Object object) + { + this.reference = object; + + jniLocalReferenceThread = new JNILocalReferenceThread(); + jniLocalReferenceThread.start(); + + // wait till JNI local reference will be created + jniLocalReferenceThread.createWhicket.waitFor(); + + reference = null; + } + + private void deleteJNILocalReference() + { + // notify JNI method that JNI local reference is not needed any more and could be released + jniLocalReferenceThread.deleteWhicket.unlock(); + + try + { + jniLocalReferenceThread.join(1000 * 60 * 2); + + if(jniLocalReferenceThread.isAlive()) + { + throw new TestBug("JNI_Local_Reference thread can't finish execution"); + } + } + catch(InterruptedException e) + { + throw new TestBug("deleteJNILocalReference was interrupted"); + } + } + + private void createJNIWeakReference(Object object) + { + referenceIndex = createJNIWeakReferenceNative(object, maxJNIWeakReferences); + + if(referenceIndex < 0) + { + throw new TestBug("Error on creation of JNI_Weak reference. Possible number of JNI_Weak references exceeded max available value!"); + } + } + + class JNILocalReferenceThread + extends Thread + { + Wicket createWhicket = new Wicket(); + Wicket deleteWhicket = new Wicket(); + + public void run() + { + createJNILocalReferenceNative(reference, createWhicket, deleteWhicket); + } + } + + private JNILocalReferenceThread jniLocalReferenceThread; + + private native int createJNIGlobalReferenceNative(Object object, int maxJNIGlobalReferences); + + private native void deleteJNIGlobalReferenceNative(int index); + + private native void createJNILocalReferenceNative(Object object, Wicket createWhicket, Wicket deleteWhicket); + + private native int createJNIWeakReferenceNative(Object object, int maxJNIWeakReferences); + + private native void deleteJNIWeakReferenceNative(int index); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObjectSet.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObjectSet.java new file mode 100644 index 00000000000..a4c778b44c2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObjectSet.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +/* + * Class create a number of referrers to given object + */ +public class ReferringObjectSet +{ + private Collection referringObjects; + private String referenceType; + + public ReferringObjectSet(Object object, int referringCount, String referenceType) + { + this.referenceType = referenceType; + referringObjects = new ArrayList(referringCount); + + for(int i = 0; i < referringCount; i++) + referringObjects.add(new ReferringObject(object, referenceType)); + } + + public void delete(int count) + { + if((count < 0) || (count > referringObjects.size())) + { + throw new TestBug("Invalid 'count' value: " + count + ", size=" + referringObjects.size()); + } + + Iterator iterator = referringObjects.iterator(); + + for(int i = 0; i < count; i++) + { + ReferringObject referringObject = iterator.next(); + referringObject.delete(); + + iterator.remove(); + } + } + + public void deleteAll() + { + delete(referringObjects.size()); + } + + public String getReferenceType() { + return referenceType; + } + + public int getReferrerCount() + { + return referringObjects.size(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/StringGoldChecker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/StringGoldChecker.java new file mode 100644 index 00000000000..50f3bbf095e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/StringGoldChecker.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +public class StringGoldChecker extends AbstractGoldChecker { + + private final String goldenString; + + public StringGoldChecker(String goldenString) { + this.goldenString = goldenString; + } + + @Override + protected String getGoldenString() { + return goldenString; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/TestBug.java b/test/hotspot/jtreg/vmTestbase/nsk/share/TestBug.java new file mode 100644 index 00000000000..fa97f8b85bd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TestBug.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +/** + * Thrown when it becomes obvious that the test algorithm + * works incorrectly (for example - tries to write to debugee's + * stdin after it is already redirected, or something of the + * kind). + */ +public class TestBug extends Failure { + /** Explain particular failure. */ + public TestBug(String message) { + super(message); + } + + /** Enwrap another throwable. */ + public TestBug(Throwable throwable) { + super(throwable); + } + + public TestBug(String message, Throwable throwable) { + super(message, throwable); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/TestFailure.java b/test/hotspot/jtreg/vmTestbase/nsk/share/TestFailure.java new file mode 100644 index 00000000000..001a0a53869 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TestFailure.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +public class TestFailure extends RuntimeException { + public TestFailure() { + super(); + } + + public TestFailure(String message) { + super(message); + } + + public TestFailure(String message, Throwable e) { + super(message, e); + } + + public TestFailure(Throwable e) { + super(e); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/TestJNIError.java b/test/hotspot/jtreg/vmTestbase/nsk/share/TestJNIError.java new file mode 100644 index 00000000000..6867c60a423 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TestJNIError.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share; + +public class TestJNIError + extends Error +{ + public TestJNIError(String message) + { + super(message); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/TimeoutHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/TimeoutHandler.java new file mode 100644 index 00000000000..7a79c672d98 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TimeoutHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.io.*; + +/** + * This class can be used to set timeout for test execution. + */ +public class TimeoutHandler { + + /** + * Test execution timeout in minutes. + */ + private int waitTime; + + /** + * Make new TimeoutHandler object for timeout value + * specified in command line arguments. + */ + public TimeoutHandler(ArgumentParser argumentHandler) { + this.waitTime = argumentHandler.getWaitTime(); + } + + /** + * Perform test execution in separate thread and wait for + * thread finishes or timeout exceeds. + */ + public void runTest(Thread testThread) { + long millisec = waitTime * 60 * 1000; + testThread.start(); + try { + testThread.join(millisec); + } catch (InterruptedException ex) { + throw new Failure(ex); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/TreeNodesDenotation.java b/test/hotspot/jtreg/vmTestbase/nsk/share/TreeNodesDenotation.java new file mode 100644 index 00000000000..95d59c9dcc5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TreeNodesDenotation.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share; + +import java.util.*; + +/** + * This denotation provides naming and indexing for nodes + * of a binary, or ternary, or n-ary tree. + * + *

      Here, n would be the length of a symbols + * string used as an alphabeth for nodes naming. For a + * binary tree, n=2, and an aplhabeth could be + * the "LR" string. This implies the following + * naming for tree nodes: + *

      + *              (empty)
      + *             /       \
      + *            L         R
      + *          /   \     /   \
      + *         LL   LR   RL   RR
      + *        /  \ /  \ /  \ /  \
      + * 
      + * + *

      Anyway, the tree root node is named with the empty + * string "" and is indexed with 2-zeroes array + * {0,0}. + * + *

      Index for a tree node is 2-elements int[] + * array. The 1st element is the node's level in a tree. + * The 2nd element is the item's number among all nodes of + * that level; provided that node items are enumerated from + * 0 to nlevel-1. + * Given a level, lexicographic order is assumed for the + * nodes of the same level. + * + *

      For example: given the above sample tree, the node + * "L" has the index {1,0}, while the + * node "RL" has the index {2,2}. + * + *

      In general case, ordering of characters used for nodes + * naming is implied by the given alphabeth. This may differ + * from the ``natural'' ordering. For example, if alphabeth + * is "ZYX...CBA", then ordering for nodes would be + * opposite to ``natural''. + */ +public class TreeNodesDenotation extends Denotation { + /** + * Symbols to denote tree nodes. + * + * @see #TreeNodeDenotation(String) + */ + private String alphabeth; + + /** + * Standard denotation for a binary tree; alphabeth + * is "LR". + * + * @see #TreeNodesDenotation(String) + */ + public TreeNodesDenotation() { + this("LR"); + } + + /** + * Denotation for nodes of a tree. + * + *

      Each tree node is marked with a string of symbols + * from the given alphabeth. A string length + * equals to the node's level. The root node is always + * denoted with the empty string. + * + *

      For example, an alphabeth for a binary + * tree could be "LR", or "01", or + * any 2-symbols string. However, "lL" or + * "rR" would be illegal because of collision + * between upper- and lower- case letters. + * + *

      In general case, it is illegal for alphabeth + * to contain two or several copies of the same symbol. + * This constructor deems lower- and upper-case variants + * of the same letter are the same symbol. + * + * @throws IllegalArgumentException If the alphabeth + * looks illegal. + */ + public TreeNodesDenotation(String alphabeth) { + if (alphabeth.length() == 0) + throw new IllegalArgumentException("empty alphabeth"); + // Check for lower- to upper- case collision: + this.alphabeth = alphabeth.toUpperCase(); + int length = this.alphabeth.length(); + Set pool = new HashSet(); // still empty + for (int i=0; iname is legal, and return the + * numeric index for the tree node denoted by the given + * name. + * + * @throws IllegalArgumentException If the name + * is illegal. + */ + public int[] indexFor(String name) { + int level = name.length(); + int factor = alphabeth.length(); + long item = 0; + for (int i=0; i Integer.MAX_VALUE) + throw new IllegalArgumentException("too long name: " + name); + }; + int[] index = new int [] { level, (int)item }; + return index; + } + + /** + * Check if the index[] is legal, and return + * a symbolic name for the tree node denoted by the + * given index[]. + * + * @throws IllegalArgumentException If the index[] + * is illegal. + */ + public String nameFor(int[] index) { + if (index.length != 2) + throw new IllegalArgumentException( + "index dimention: " + index.length); + StringBuffer name = new StringBuffer(); // still empty + int level = index[0]; + int item = index[1]; + if (level < 0 || item < 0) + throw new IllegalArgumentException( + "negative index: " + level + ", " + item); + int factor = alphabeth.length(); + for (int i=0; iWicket instances are intended to be used generally in the following + * scenarios: + * + *

      • One thread starts one or more child threads and waits until the + * child threads to be started. + * + *
      • One thread starts one or more child threads and waits until at least + * one of the child threads to be started. + * + *
      • One or more child threads wait until a main thread lets them + * to finish. + * + *
      • Disable the current thread for thread scheduling purposes, for up to + * the specified waiting time.
      + */ + +public class Wicket { + + /** Number of closed locks, can be greater or equal to zero */ + private int count; + + /** Number of waiters **/ + private int waiters = 0; + + /** Enable debug output */ + private PrintStream debugOutput = null; + + /** Wicket's string identifier */ + private String name = ""; + + /** + * Construct a Wicket with only one closed lock. + */ + public Wicket() { + this(1); + } + + /** + * Construct a Wicket with the given number of closed locks. + * + * @param _name Wicket's identifier + * @param _count the initial number of closed locks + * @param _debugOutput whether to print debug info or not + * @throws IllegalArgumentException if count is less than 1 + */ + public Wicket(String _name, int _count, PrintStream _debugOutput) { + this(_count); + name = _name; + debugOutput = _debugOutput; + } + + /** + * Construct a Wicket with the given number of closed locks. + * + * @param count the initial number of closed locks + * @throws IllegalArgumentException if count is less than 1 + */ + public Wicket(int count) { + if (count < 1) + throw new IllegalArgumentException( + "count is less than one: " + count); + this.count = count; + } + + /** + * Wait for all locks of this Wicket to be open. + * + *

      If all locks are already open then returns immediately. + * + *

      If at least one lock is still closed then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until all + * the locks will be open by some other threads. One lock can be open + * by invoking the unlock method for this Wicket. + * + *

      Please note, that the method would ignore Thread.interrupt() requests. + */ + public synchronized void waitFor() { + ++waiters; + if (debugOutput != null) { + debugOutput.printf("Wicket %s: waitFor()\n", name); + } + + while (count > 0) { + try { + wait(); + } catch (InterruptedException e) {} + } + --waiters; + } + + /** + * Wait for all locks of this Wicket to be open within the given + * period of time. + * + *

      If all locks are already open then returns immediately with zero. + * + *

      If the time is equal to zero, the method will not + * wait and returns a number of closed locks, + * if all locks are open, the return value is zero. + * + *

      If at least one lock is still closed then the current thread becomes + * disabled for thread scheduling purposes and lies dormant until + * of the two things happens: + * + *

      • Some other threads invoke the unlock method for this Wicket + * to open all the closed locks; or + * + *
      • The specified waiting time elapses.
      + * + *

      If all locks are open then the return value is 0. + * + *

      If the specified waiting time elapses and some locks are still closed + * then the return value is equal to number of closed locks. + * + *

      Please note, that the method would ignore Thread.interrupt() requests. + * + * @param timeout the maximum time to wait in milliseconds + * @return the number of closed locks + * @throws IllegalArgumentException if timeout is less than 0 + */ + public synchronized int waitFor(long timeout) { + if (debugOutput != null) { + debugOutput.printf("Wicket %s: waitFor(%d)\n", name, timeout); + } + + if (timeout < 0) + throw new IllegalArgumentException( + "timeout value is negative: " + timeout); + ++waiters; + long waitTime = timeout; + long startTime = System.currentTimeMillis(); + while (count > 0 && waitTime > 0) { + try { + wait(waitTime); + } catch (InterruptedException e) {} + waitTime = timeout - (System.currentTimeMillis() - startTime); + } + --waiters; + return (count); + } + + /** + * Unlock one closed lock. + * + *

      Open a lock, reducing the number of closed locks by one. + * + *

      If last closed lock is opened then all of the threads waiting + * by invoking the waitFor method for this Wicket will be released + * and re-enabled for thread scheduling purposes. + * + * @throws IllegalStateException if there is no one closed lock + */ + public synchronized void unlock() { + if (debugOutput != null) { + debugOutput.printf("Wicket %s: unlock()\n", name); + } + + if (count == 0) + throw new IllegalStateException("locks are already open"); + + --count; + if (count == 0) { + notifyAll(); + } + } + + /** + * Unlock all closed locks. + * + *

      Open all closed locks, setting the number of closed locks to zero. + * + *

      If any threads are waiting by invoking the waitFor method for + * this Wicket then they will be released and re-enabled for thread + * scheduling purposes. + */ + public synchronized void unlockAll() { + if (debugOutput != null) { + debugOutput.printf("Wicket %s: unlockAll()\n", name); + } + + count = 0; + notifyAll(); + } + + /** + * Return current number of waiters - threads that are currently + * waiting using one of waitFor methods. + * + * @return number of waiters + */ + public synchronized int getWaiters() { + if (debugOutput != null) { + debugOutput.printf("Wicket %s: getWaiters()\n", name); + } + return waiters; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODRunnerArgParser.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODRunnerArgParser.java new file mode 100644 index 00000000000..e6a961dc08d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODRunnerArgParser.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import nsk.share.*; +import java.util.*; + +public class AODRunnerArgParser extends ArgumentParser { + + public static final String jarAgentParam = "ja"; + + public static final String nativeAgentParam = "na"; + + public static final String targetAppParam = "target"; + + public static final String javaOptsParam = "javaOpts"; + + public static final String testedJdkParam = "jdk"; + + private static List supportedOptions; + + static { + supportedOptions = new ArrayList(); + supportedOptions.add(jarAgentParam); + supportedOptions.add(nativeAgentParam); + supportedOptions.add(targetAppParam); + supportedOptions.add(javaOptsParam); + supportedOptions.add(testedJdkParam); + } + + private List agents; + + public AODRunnerArgParser(String[] args) { + super(args); + } + + protected boolean checkOption(String option, String value) { + if (super.checkOption(option, value)) + return true; + + if (!supportedOptions.contains(option)) + return false; + + if (option.equals(jarAgentParam)) { + addAgentInfo(true, value); + } + + if (option.equals(nativeAgentParam)) { + addAgentInfo(false, value); + } + + return true; + } + + protected void checkOptions() { + if (agents == null) { + agents = new ArrayList(); + } + } + + private void addAgentInfo(boolean jarAgent, String unsplittedAgentsString) { + if (agents == null) { + agents = new ArrayList(); + } + + String agentStrings[]; + + if (unsplittedAgentsString.contains(",")) + agentStrings = unsplittedAgentsString.split(","); + else + agentStrings = new String[]{unsplittedAgentsString}; + + for (String agentString : agentStrings) { + int index = agentString.indexOf('='); + + if (index > 0) { + String pathToAgent = agentString.substring(0, index); + String options = agentString.substring(index + 1); + agents.add(new AgentInformation(jarAgent, pathToAgent, options)); + } else { + agents.add(new AgentInformation(jarAgent, agentString, null)); + } + } + } + + public String getTargetApp() { + if (!options.containsKey(targetAppParam)) + throw new TestBug("Target application isn't specified"); + + return options.getProperty(targetAppParam); + } + + public String getTestedJDK() { + if (!options.containsKey(testedJdkParam)) + throw new TestBug("Tested JDK isn't specified"); + + return options.getProperty(testedJdkParam); + } + + public String getJavaOpts() { + return options.getProperty(javaOptsParam, ""); + } + + public List getAgents() { + return agents; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTargetArgParser.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTargetArgParser.java new file mode 100644 index 00000000000..a8cdd2c6a19 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTargetArgParser.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import nsk.share.*; +import java.util.*; + +public class AODTargetArgParser extends ArgumentParser { + + public static final String agentsNumberParam = "agentsNumber"; + + public static final String socketPortParam = "port"; + + private int expectedAgentsNumber; + + private int port; + + private static List supportedOptions; + + static { + supportedOptions = new ArrayList(); + supportedOptions.add(agentsNumberParam); + supportedOptions.add(socketPortParam); + } + + public AODTargetArgParser(String[] args) { + super(args); + } + + protected boolean checkOption(String option, String value) { + if (super.checkOption(option, value)) + return true; + + if (!supportedOptions.contains(option)) + return false; + + if (option.equals(agentsNumberParam)) { + expectedAgentsNumber = Integer.parseInt(value); + if (expectedAgentsNumber < 0) + throw new TestBug("Invalid value of '" + option + "'"); + } else if (option.equals(socketPortParam)) { + port = Integer.parseInt(value); + if (port <= 0 || port > 65535) + throw new TestBug("Invalid value of '" + option + "':" + port +" (it is expected to be in the range [1..65535]"); + } + + return true; + } + + public int getExpectedAgentsNumber() { + if (!options.containsKey(agentsNumberParam)) + throw new TestBug("Number of expected agents isn't specified"); + + return expectedAgentsNumber; + } + + public int getPort() { + if (!options.containsKey(socketPortParam)) + return -1; + + return port; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java new file mode 100644 index 00000000000..2fa58139da4 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import java.io.*; +import nsk.share.*; +import nsk.share.jpda.SocketIOPipe; + +/* + Class AODTestRunner is part of the framework used in the AttachOnDemand tests + (tests against Attach API, API from package com.sun.tools.attach). + + AODTestRunner is used as main class in AttachOnDemand tests, it performs following + actions: + - starts target application + + - finds VM id for target VM (this id is needed for dynamic attach) + + - by default AODTestRunner tries to attach specified via command line agents to target VM + (subclasses can override this default behavior) + + - waits for target application completion + +Target application class, agents that should be attached, JDK used to run target application and +VM options passed to target VM should be specified via command line. + */ +public class AODTestRunner { + + public static final String targetAppIdProperty = "vmsqe.aod.targetAppId"; + public static final String appIdProperty = "vmsqe.aod.AppId"; + + public static final long TARGET_APP_CONNECT_TIMEOUT = 5 * 60 * 1000; // 5 min + + public static final long TARGET_APP_WORK_TIMEOUT = 30 * 60 * 1000; // 30 min (standard VM testbase test timeout) + + protected Log log; + + protected SocketIOPipe pipe; + + protected ProcessExecutor targetAppExecutor; + + // target application ready for attach + public static final String SIGNAL_READY_FOR_ATTACH = "ready"; + + // target application may finish execution + public static final String SIGNAL_FINISH = "finish"; + + protected AODRunnerArgParser argParser; + + protected AODTestRunner(String[] args) { + log = new Log(System.out, true); + + argParser = createArgParser(args); + } + + /* + * This method is introduced to let subclasses to create its own parsers + */ + protected AODRunnerArgParser createArgParser(String[] args) { + return new AODRunnerArgParser(args); + } + + protected void doTestActions(String targetVMId) throws Throwable { + AgentsAttacher attacher = new AgentsAttacher(targetVMId, argParser.getAgents(), log); + attacher.attachAgents(); + } + + protected String getCurrentVMId() { + String currentVMId = "" + ProcessHandle.current().pid(); + log.display("Current VM id was identified: " + currentVMId); + + return currentVMId; + } + + protected void runTest() { + + try { + String targetAppId = System.getProperty(targetAppIdProperty); + if(targetAppId == null || targetAppId.isEmpty()) { + // use PID as default appID + targetAppId = "" + ProcessHandle.current().pid(); + } + /* + * Create target application id required by the Utils.findVMIdUsingJPS + */ + String targetAppCmd = + // path to java + argParser.getTestedJDK() + File.separator + "bin" + File.separator + "java " + + // VM property to identify VM running target application + "-D" + appIdProperty + "=" + targetAppId + " " + + // VM opts + argParser.getJavaOpts() + " -XX:+EnableDynamicAgentLoading " + + // target application class + argParser.getTargetApp() + " " + + // additional target application parameter - number of + // agents that will be attached + "-" + AODTargetArgParser.agentsNumberParam + " " + argParser.getAgents().size(); + + pipe = SocketIOPipe.createServerIOPipe(log, 0, TARGET_APP_CONNECT_TIMEOUT); + targetAppCmd += " -" + AODTargetArgParser.socketPortParam + " " + pipe.getPort(); + + log.display("Starting target application: " + targetAppCmd); + targetAppExecutor = new ProcessExecutor(targetAppCmd, TARGET_APP_WORK_TIMEOUT, "TargetApp"); + targetAppExecutor.startProcess(); + + /* + * Don't try to attach agents until target application isn't initialized + */ + String signal = pipe.readln(); + log.display("Signal received: '" + signal + "'"); + if ((signal == null) || !signal.equals(SIGNAL_READY_FOR_ATTACH)) + throw new TestBug("Unexpected TargetApplication signal: '" + signal + "'"); + + String targetVMId = Long.toString(targetAppExecutor.pid()); + log.display("Target VM id was identified: " + targetVMId); + + doTestActions(targetVMId); + + /* + * When test actions finished let target application finish execution + */ + log.display("Sending signal: '" + SIGNAL_FINISH + "'"); + pipe.println(SIGNAL_FINISH); + + targetAppExecutor.waitForProcess(); + + File file = new File(targetAppId); + if (file.exists()) { + file.deleteOnExit(); + } + + if (targetAppExecutor.getExitCode() != 0) { + throw new Failure("Target application finished with non-zero code " + targetAppExecutor.getExitCode()); + } + + postTargetExitHook(); + + } catch (Failure f) { + throw f; + } catch (Throwable t) { + throw new Failure("Unexpected exception during test execution: " + t, t); + } finally { + if (pipe != null) { + pipe.close(); + } + if (targetAppExecutor != null) { + targetAppExecutor.destroyProcess(); + } + } + } + + /* + * Allow users of this class to specify actions to be taken after the target exits + */ + protected void postTargetExitHook() { + // do nothing by default + } + + public static String createApplicationId() { + return new Long(System.currentTimeMillis()).toString(); + } + + public static void main(String[] args) { + new AODTestRunner(args).runTest(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java new file mode 100644 index 00000000000..3fa3141a8cd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import java.lang.instrument.*; +import java.io.*; +import nsk.share.*; + +/* + +AbstractJarAgent is base class for java agents used in AttachOnDemand tests +(tests against Attach API, API from package com.sun.tools.attach). + +In all AttachOnDemand tests the same algorithm is used: + - java application where agent is loaded to (target application) based on + class nsk.share.aod.TargetApplicationWaitingAgents starts and waits when + test agents will be loaded + + - special application (nsk.share.jvmti.aod.AgentsAttacher) loads test agents + in the target application using Attach API + + - when agent is loaded it notifies target application about that and executes + test-specific actions. When agent execution is completed it also notifies + target application about that + + - when all test agents finish execution target application checks its status + (passed or failed) and also finishes + +Each java agent should have method 'agentmain' where only agent initialization should be done, +main agent's actions should be executed in special thread started from 'agentmain'. +Class AbstractJarAgent incapsulates actions common for all java agents: agent initialization, +starting thread executing agent's actions and communication with target application. + +In most cases test agents should override only method 'agentActions' and its 'agentmain' +should contain only call of the method 'AbstractJarAgent.runJarAgent'. + +Typical agent class looks like this: + +public class agentExample extends AbstractJarAgent { + + protected void init(String[] args) { + // parse agent's options and do test-specific initialization + } + + protected void agentActions() { + // do test specific actions + } + + public static void agentmain(final String options, Instrumentation inst) { + new agentExample().runJarAgent(options, inst); + } +} + */ +abstract public class AbstractJarAgent { + + private boolean finishedSuccessfully = true; + + private Log log; + + protected void display(String message) { + log.display(outputPrefix + message); + } + + protected void complain(String message) { + log.complain(outputPrefix + message); + } + + protected void logThrowable(Throwable t) { + t.printStackTrace(log.getOutStream()); + } + + /* + * Instrumentation object passed to the 'agentmain' method + */ + protected Instrumentation inst; + + private String name; + + private String outputPrefix; + + private String pathToNewByteCode; + + protected String pathToNewByteCode() { + return pathToNewByteCode; + } + + /* + * Subclasses should report about test failures using this method + */ + protected void setStatusFailed(String errorMessage) { + finishedSuccessfully = false; + complain("ERROR: " + errorMessage); + } + + /* + * Initialization method, called from agentmain before method agentActions is called + * (it introduced for overriding in subclasses) + */ + protected void init(String[] args) { + } + + protected static class AgentOption { + public String name; + public String value; + public AgentOption(String name, String value) { + this.name = name; + this.value = value; + } + } + + protected AgentOption parseAgentArgument(String arg) { + int index = arg.indexOf('='); + if (index <= 0) { + throw new TestBug("Invalid agent parameters format"); + } + return new AgentOption(arg.substring(0, index), arg.substring(index + 1)); + } + + static protected final String agentNameOption = "-agentName"; + + static protected final String pathToNewByteCodeOption = "-pathToNewByteCode"; + + /* + * Parse agent's options, initialize common parameters + */ + private void defaultInit(String[] args) { + for (int i = 0; i < args.length; i++) { + AgentOption option = parseAgentArgument(args[i]); + if (option.name.equals(agentNameOption)) { + name = option.value; + outputPrefix = name + ": "; + } else if (option.name.equals(pathToNewByteCodeOption)) { + pathToNewByteCode = option.value; + } + } + + if (name == null) + throw new TestBug("Agent name wasn't specified"); + + log = new Log(System.out, true); + } + + /* + * Special thread which is started from agentmain method and executing main + * agent's actions. When agent completes execution AgentThread notifies + * target application about that. + */ + class AgentThread extends Thread { + + AgentThread() { + super("Jar agent thread (agent: " + name + ")"); + } + + public void run() { + try { + agentActions(); + } catch (Throwable t) { + setStatusFailed("Unexpected exception in the JarAgent: " + t); + logThrowable(t); + } finally { + TargetApplicationWaitingAgents.agentFinished(name, finishedSuccessfully); + } + } + } + + /* + * This methods parses agent's options, initializes agent, notifies target application + * that agent is started and starts thread executing main agent's actions. + * Agents used in AttachOnDemand tests should call this method from its agentmain methods. + */ + public final void runJarAgent(String options, Instrumentation inst) { + if (options == null) + throw new TestBug("Agent options weren't specified"); + + this.inst = inst; + + String[] args = options.split(" "); + + // initialize common parameters + defaultInit(args); + + // test-specific initialization + init(args); + + // notify target application that agent was loaded and initialized + TargetApplicationWaitingAgents.agentLoaded(name); + + // start special thread executing test-specific actions + new AgentThread().start(); + } + + /* + * Actions specific for test should be realized in this method. + * This method is called from special thread started from agentmain method + * after agent initialization + */ + abstract protected void agentActions() throws Throwable; + + + /* + * Create ClassDefinition object for given class, path to the new class file + * is specified in the parameter 'pathToByteCode' + */ + protected static ClassDefinition createClassDefinition(Class klass, + String pathToByteCode) throws IOException { + File classFile = new File(pathToByteCode + File.separator + + klass.getName().replace(".", File.separator) + + ".class"); + + if (classFile.length() > Integer.MAX_VALUE) + throw new Failure("Class file '" + classFile.getName() + " 'too large"); + + byte data[] = new byte[(int)classFile.length()]; + + DataInputStream in = null; + try { + in = new DataInputStream(new FileInputStream(classFile)); + in.readFully(data); + } finally { + if (in != null) + in.close(); + } + + return new ClassDefinition(klass, data); + } + + /* + * Redefine given class using path to byte code specified with options -pathToNewByteCode + */ + protected void redefineClass(Class klass) throws Throwable { + if (pathToNewByteCode() == null) + throw new TestBug("Path to new class files wasn't specified"); + + ClassDefinition newClassDef = createClassDefinition(klass, pathToNewByteCode()); + inst.redefineClasses(newClassDef); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentInformation.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentInformation.java new file mode 100644 index 00000000000..312aad7470e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentInformation.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +/* + * Class contains information about dynamically attached agent + */ +public class AgentInformation { + + // counters used for unique agent names generation + + private static int jarAgentsCounter; + + private static int nativeAgentsCounter; + + public boolean jarAgent; + + public String pathToAgent; + + public String agentOptions; + + public AgentInformation(boolean jarAgent, String pathToAgent, String options, boolean addAgentNameOption) { + this.jarAgent = jarAgent; + this.pathToAgent = pathToAgent; + this.agentOptions = options; + + // add to agent options additional parameter - agent name (it used by nsk.share.aod framework) + + String name; + + if (jarAgent) + name = "JarAgent-" + jarAgentsCounter++; + else + name = "NativeAgent-" + nativeAgentsCounter++; + + if (addAgentNameOption) { + if (this.agentOptions == null) { + this.agentOptions = "-agentName=" + name; + } else { + this.agentOptions += " -agentName=" + name; + } + } + } + + public AgentInformation(boolean jarAgent, String pathToAgent, String options) { + this(jarAgent, pathToAgent, options, true); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentsAttacher.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentsAttacher.java new file mode 100644 index 00000000000..c502ca33c8d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentsAttacher.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import nsk.share.*; +import java.io.IOException; +import java.util.*; +import com.sun.tools.attach.*; + +/* + * This class loads java and native agents in the running VM using Attach API + * (API from package com.sun.tools.attach). + */ +public class AgentsAttacher { + + protected String targetVMId; + + protected List agents; + + protected Log log; + + public AgentsAttacher(String targetVMId, List agents, Log log) { + this.targetVMId = targetVMId; + this.agents = agents; + this.log = log; + } + + public void attachAgents() { + VirtualMachine vm = null; + + try { + log.display("Trying to get VirtualMachine object"); + vm = VirtualMachine.attach(targetVMId); + } catch (AttachNotSupportedException e) { + log.complain("Unexpected AttachNotSupportedException during VirtualMachine.attach: " + e); + e.printStackTrace(log.getOutStream()); + } catch (IOException e) { + log.complain("Unexpected IOException during VirtualMachine.attach: " + e); + e.printStackTrace(log.getOutStream()); + } + + if (vm == null) { + failed("Unable to create VirtualMachine object"); + } + + log.display("VirtualMachine was created: " + vm); + + try { + for (AgentInformation agentInfo : agents) { + tryToLoadAgent(vm, agentInfo.pathToAgent, agentInfo.agentOptions, agentInfo.jarAgent); + } + } finally { + try { + log.display("Detaching from the VM '" + vm + "'"); + vm.detach(); + } catch (IOException e) { + failed("Unexpected IOException during detaching: " + e, e); + } + } + } + + protected void tryToLoadAgent(VirtualMachine vm, String agent, String agentOptions, boolean jarAgent) { + boolean agentLoaded = false; + + Throwable failureCause = null; + + try { + if (jarAgent) { + log.display("Trying to load jar agent: '" + agent + "' (agent options: '" + agentOptions + "')"); + vm.loadAgent(agent, agentOptions); + } else { + log.display("Trying to load native agent: '" + agent + "' (agent options: '" + agentOptions + "')"); + vm.loadAgentLibrary(agent, agentOptions); + } + log.display("Agent was loaded"); + agentLoaded = true; + } catch (AgentLoadException e) { + failureCause = e; + log.complain("Unexpected AgentLoadException during agent loading: " + e); + if (jarAgent) { + log.complain("(probably the agent does not exist, or cannot be started in the manner specified in " + + "the java.lang.instrument specification)"); + } else { + log.complain("(probably agent library does not exist, or cannot be loaded for another reason)"); + } + e.printStackTrace(log.getOutStream()); + } catch (AgentInitializationException e) { + failureCause = e; + log.complain("Unexpected AgentInitializationException during agent loading: " + e); + if (jarAgent) { + log.complain("(agentmain have thrown an exception)"); + } else { + log.complain("Agent_OnAttach function returned an error: " + e.returnValue()); + } + e.printStackTrace(log.getOutStream()); + } catch (IOException e) { + failureCause = e; + log.complain("Unexpected IOException during agent loading: " + e); + e.printStackTrace(log.getOutStream()); + } + + if (!agentLoaded) { + if (failureCause != null) + failed("Couldn't attach agent to the target application", failureCause); + else + failed("Couldn't attach agent to the target application"); + } + } + + private void failed(String errorMessage) { + throw new Failure(errorMessage); + } + + private void failed(String errorMessage, Throwable t) { + throw new Failure(errorMessage, t); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java new file mode 100644 index 00000000000..d628991a4b2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import nsk.share.*; +import nsk.share.jpda.SocketIOPipe; + +/* +Class TargetApplication is part of the framework used in the AttachOnDemand tests +(tests against Attach API, API from package com.sun.tools.attach). + +This class is used in tests where main test application uses Attach API, but doesn't load agents to the another VM. +In these test there are 2 java applications: main application using Attach API and another +'dummy' application which should be alive while main application is working. + +To synchronize main and dummy application SocketIOPipe is used: when DummyTargetApplication starts +it sends signal that it is ready for test and waits for signal permitting finish execution +(socket number used for connection establishing should be passed via command line). + */ +public class DummyTargetApplication { + + protected Log log = new Log(System.out, true); + + protected AODTargetArgParser argParser; + + protected SocketIOPipe pipe; + + public DummyTargetApplication(String[] args) { + argParser = new AODTargetArgParser(args); + } + + protected void targetApplicationActions() { + // do nothing by default + } + + public void runTargetApplication() { + pipe = SocketIOPipe.createClientIOPipe(log, "localhost", argParser.getPort(), 0); + log.display("Sending signal '" + AODTestRunner.SIGNAL_READY_FOR_ATTACH + "'"); + pipe.println(AODTestRunner.SIGNAL_READY_FOR_ATTACH); + + targetApplicationActions(); + + String signal = pipe.readln(); + log.display("Signal received: '" + signal + "'"); + + if ((signal == null) || !signal.equals(AODTestRunner.SIGNAL_FINISH)) + throw new TestBug("Unexpected signal: '" + signal + "'"); + } + + public static void main(String[] args) { + new DummyTargetApplication(args).runTargetApplication(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/ProcessExecutor.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/ProcessExecutor.java new file mode 100644 index 00000000000..3d8a87f3f97 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/ProcessExecutor.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import java.io.*; +import java.util.*; +import nsk.share.*; + +public class ProcessExecutor { + + private String[] cmdLine; + + private long timeout; + + private boolean printProcessOutput; + + private String processOutputPrefix; + + private InputStreamReaderThread outReader; + + private InputStreamReaderThread errReader; + + private Process startedProcess; + + private ProcessWaiterThread processWaiter; + + private long expectedFinishTime; + + private volatile boolean executionCompleted; + + private int exitCode; + + private class InputStreamReaderThread extends Thread { + private BufferedReader in; + + private String outputPrefix; + + private List output = new ArrayList(); + + private volatile boolean streamWasAbruptlyClosed; + + private Throwable unexpectedException; + + public InputStreamReaderThread(InputStream in, String prefix) { + this.in = new BufferedReader(new InputStreamReader(in)); + this.outputPrefix = prefix; + setDaemon(true); + } + + public void streamWasAbruptlyClosed(boolean newValue) { + streamWasAbruptlyClosed = newValue; + } + + public void run() { + try { + while (true) { + String line = in.readLine(); + if (line == null) + return; + + output.add(line); + + if (printProcessOutput) + System.out.println(outputPrefix + line); + } + } catch (IOException e) { + if (!streamWasAbruptlyClosed) { + unexpectedException = e; + e.printStackTrace( ); + } + } catch (Throwable t) { + unexpectedException = t; + t.printStackTrace( ); + } + } + + void checkStatus() { + if (unexpectedException != null) + throw new Failure("Exception was thrown during InputStreamReaderThread work: " + unexpectedException, + unexpectedException); + } + } + + private class ProcessWaiterThread extends Thread { + + private Throwable unexpectedException; + + private Process process; + + private InputStreamReaderThread outReader; + + private InputStreamReaderThread errReader; + + ProcessWaiterThread(Process process, InputStreamReaderThread outReader, InputStreamReaderThread errReader) { + this.process = process; + this.outReader = outReader; + this.errReader = errReader; + + setDaemon(true); + } + + public void run() { + try { + exitCode = process.waitFor(); + outReader.join(); + errReader.join(); + + synchronized (ProcessWaiterThread.this) { + executionCompleted = true; + ProcessWaiterThread.this.notify(); + } + } catch (InterruptedException e) { + /* + * ProcessWaiterThread is interrupted if started process + * didn't finish in expected time + */ + } catch (Throwable t) { + unexpectedException = t; + t.printStackTrace(); + } + } + + void checkStatus() { + if (unexpectedException != null) + throw new Failure("Exception was thrown during ProcessWaiterThread work: " + + unexpectedException, unexpectedException); + } + } + + public ProcessExecutor(String cmdLine, long timeout) { + this.cmdLine = new String[]{cmdLine}; + this.timeout = timeout; + } + + public ProcessExecutor(String cmdLine, long timeout, String outputPrefix) { + this(cmdLine, timeout); + this.printProcessOutput = true; + this.processOutputPrefix = outputPrefix; + } + + public void startProcess() throws IOException { + if (cmdLine.length == 1) + startedProcess = Runtime.getRuntime().exec(cmdLine[0]); + else + startedProcess = Runtime.getRuntime().exec(cmdLine); + + expectedFinishTime = System.currentTimeMillis() + timeout; + + outReader = new InputStreamReaderThread(startedProcess.getInputStream(), + processOutputPrefix == null ? "" : processOutputPrefix + " (stdout): "); + errReader = new InputStreamReaderThread(startedProcess.getErrorStream(), + processOutputPrefix == null ? "" : processOutputPrefix + " (stderr): "); + + outReader.start(); + errReader.start(); + + processWaiter = new ProcessWaiterThread(startedProcess, outReader, errReader); + processWaiter.start(); + } + + + public void waitForProcess() throws InterruptedException { + synchronized (processWaiter) { + while ((System.currentTimeMillis() < expectedFinishTime) && !executionCompleted) { + processWaiter.wait(expectedFinishTime - System.currentTimeMillis()); + } + } + + if (!executionCompleted) { + destroyProcessAndWaitThreads(); + + executionCompleted = true; + + throw new Failure("Execution timed out (timeout: " + timeout + "ms)"); + } + } + + private void destroyProcessAndWaitThreads() { + outReader.streamWasAbruptlyClosed(true); + errReader.streamWasAbruptlyClosed(true); + + processWaiter.interrupt(); + startedProcess.destroy(); + + try { + outReader.join(); + errReader.join(); + processWaiter.join(); + + outReader.checkStatus(); + errReader.checkStatus(); + processWaiter.checkStatus(); + } catch (InterruptedException e) { + throw new Failure("Unexpected InterruptedException", e); + } + } + + private void checkProcessState() { + if (!executionCompleted) + throw new IllegalStateException("Process didn't finish execution"); + } + + public void destroyProcess() { + if (executionCompleted) + return; + + destroyProcessAndWaitThreads(); + } + + public long pid() { + return startedProcess.pid(); + } + + public int getExitCode() { + checkProcessState(); + + return exitCode; + } + + public List getProcessOut() { + checkProcessState(); + + return outReader.output; + } + + public List getProcessErr() { + checkProcessState(); + + return errReader.output; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java new file mode 100644 index 00000000000..67f4896ea3b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import nsk.share.*; +import nsk.share.jpda.SocketIOPipe; + +import java.util.*; + +/* +Class TargetApplicationWaitingAgents is part of the framework used in the AttachOnDemand tests +(tests against Attach API, API from package com.sun.tools.attach). + +Attach API allows to load so called 'agents' in the running VM. In terms of this framework +application running in the VM where agent is loaded to is called 'target application'. + +TargetApplicationWaitingAgents is base class for target applications used in the AttachOnDemand tests +(also TargetApplicationWaitingAgents can be used without modifications in tests where target +application shouldn't execute some test-specific actions). + +AttachOnDemand tests requires synchronization between test agents and target application: + - before target application can start to execute test-specific actions it + should wait when all tests agents will be loaded + + - target application shouldn't finish until all agents finish their work + +TargetApplicationWaitingAgents incapsulates actions common for all target applications. TargetApplicationWaitingAgents +provides 2 methods: 'agentLoaded' and 'agentFinished', test agents use these methods to notify +target application about its status. When target application based on the TargetApplicationWaitingAgents +starts it first waits when all test agents will be loaded (number of expected test agents is +passed via parameter -agentsNumber). After this target application executes test-specific actions, +waits when all test agents will finish, checks agent's status (passed of failed) and +finishes. + +In most cases test target applications should override only method 'targetApplicationActions' and +its 'main' method should contain only call of the method 'TargetApplicationWaitingAgents.runTargetApplication'. + +Typical target application class looks like this: + +public class targetExample extends TargetApplicationWaitingAgents { + + protected void targetApplicationActions() { + // do test-specific actions + } + + public static void main(String[] args) { + new targetExample().runTargetApplication(args); + } +} +*/ +public class TargetApplicationWaitingAgents { + + private volatile static boolean testFailed = false; + + private static long AGENTS_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 min + + private static long AGENTS_FINISHING_TIMEOUT = 5 * 60 * 1000; // 5 min + + private static boolean allAgentsAttached; + + private static List attachedAgents = new ArrayList(); + + private static boolean allAgentsFinished; + + private static List finishedAgents = new ArrayList(); + + private static boolean targetApplicationInitialized; + + static protected AODTargetArgParser argParser; + + protected static Log log; + + static private Object monitor = new Object(); + + /* + * Methods + * - agentLoaded(String agentName) and + * - agentFinished(String agentName, boolean finishedSuccessfully) + * are called from test agents to notify target application about its status + */ + + public static void agentLoaded(String agentName) { + synchronized (monitor) { + if (!targetApplicationInitialized) + waitForTargetApplicationInitialization(); + + // check test logic + if (attachedAgents.contains(agentName)) { + setStatusFailed("Agent '" + agentName + "' already attached"); + + // let TargetApplication complete execution in case of error + allAgentsAttached = true; + monitor.notifyAll(); + + throw new TestBug("Agent '" + agentName + "' calls method 'agentLoaded' more than 1 time"); + } else { + attachedAgents.add(agentName); + + log.display("Agent '" + agentName + "' was loaded"); + + allAgentsAttached = (attachedAgents.size() == argParser.getExpectedAgentsNumber()); + + if (allAgentsAttached) + monitor.notifyAll(); + + // check test logic + if (attachedAgents.size() > argParser.getExpectedAgentsNumber()) { + setStatusFailed("Unexpected agent attached (expected agents number: " + + argParser.getExpectedAgentsNumber() + + ", but " + attachedAgents.size() + " agents were loaded)"); + + throw new TestBug("More agents attached than it was expected" + + " (expected: " + argParser.getExpectedAgentsNumber() + + ", attached: " + attachedAgents.size() + ")"); + } + } + } + } + + public static void agentFinished(String agentName, boolean finishedSuccessfully) { + synchronized (monitor) { + // check test logic + if (!targetApplicationInitialized) + throw new TestBug("Method 'agentFinished' was called before TargetApplication was initialized"); + + boolean algorithmError = false; + String errorMessage = "Test algorithm error:"; + + if (!attachedAgents.contains(agentName)) { + algorithmError = true; + errorMessage += " agent '" + agentName + "' didn't call method 'agentLoaded';"; + log.complain(errorMessage); + } + + if (finishedAgents.contains(agentName)) { + algorithmError = true; + errorMessage += " agent '" + agentName + "' already called method 'agentFinished';"; + log.complain(errorMessage); + } + + if (algorithmError) { + // let TargetApplication complete execution in case of error + allAgentsFinished = true; + monitor.notifyAll(); + + throw new TestBug(errorMessage); + } else { + finishedAgents.add(agentName); + + log.display("Agent '" + agentName + "' finished execution (finishedSuccessfully: " + finishedSuccessfully + ")"); + + if (!finishedSuccessfully) + setStatusFailed("Agent '" + agentName + " finished with error status"); + + allAgentsFinished = (finishedAgents.size() == argParser.getExpectedAgentsNumber()); + + if (allAgentsAttached) + monitor.notifyAll(); + } + } + } + + /* + * This method is called from the method 'agentLoaded' in case + * when target application isn't initialized yet at the moment + * when agent is connecting + */ + static private void waitForTargetApplicationInitialization() { + synchronized (monitor) { + while (!targetApplicationInitialized) { + try { + monitor.wait(); + } catch (InterruptedException e) { + // should never happen + exitAsFailed(e); + } + } + } + } + + /* + * This method is introduced to let subclasses to create its own parsers + */ + protected AODTargetArgParser createArgParser(String[] args) { + return new AODTargetArgParser(args); + } + + /* + * Target application initialization + */ + private void initTargetApplication(String[] args) { + synchronized (monitor) { + if (targetApplicationInitialized) + throw new TestBug("TargetApplication already initialized"); + + log = new Log(System.out, true); + + argParser = createArgParser(args); + + // test-specific initialization + init(args); + + targetApplicationInitialized = true; + monitor.notifyAll(); + } + } + + static private void waitAgentsConnection() { + synchronized (monitor) { + long waitFinishTime = System.currentTimeMillis() + AGENTS_CONNECTION_TIMEOUT; + + while (!allAgentsAttached && (System.currentTimeMillis() < waitFinishTime)) { + try { + monitor.wait(AGENTS_CONNECTION_TIMEOUT); + } catch (InterruptedException e) { + // should never happen + exitAsFailed(e); + } + } + } + + if (!allAgentsAttached) { + exitAsFailed("Agents didn't attach in " + AGENTS_CONNECTION_TIMEOUT + "ms, stop execution " + + "(expected agents number: " + argParser.getExpectedAgentsNumber() + + ", attached agents number: " + attachedAgents.size() + ")"); + } + } + + static private void waitAgentsFinishing() { + synchronized (monitor) { + long waitFinishTime = System.currentTimeMillis() + AGENTS_FINISHING_TIMEOUT; + + while (!allAgentsFinished && (System.currentTimeMillis() < waitFinishTime)) { + try { + monitor.wait(AGENTS_FINISHING_TIMEOUT); + } catch (InterruptedException e) { + // should never happen + exitAsFailed(e); + } + } + } + + if (!allAgentsFinished) + exitAsFailed("Agents didn't finish in " + AGENTS_FINISHING_TIMEOUT + "ms, stop execution " + + "(attached agents number: " + attachedAgents.size() + + ", finished agents number: " + finishedAgents.size() + ")"); + } + + /* + * Print error message and set failed status, but don't exit + */ + + static public void setStatusFailed(String message) { + testFailed = true; + log.complain(message); + } + + static public void setStatusFailed(Throwable t) { + testFailed = true; + log.complain("Unexpected exception: " + t); + t.printStackTrace(log.getOutStream()); + } + + /* + * Print error message and exit with fail status + */ + static protected void exitAsFailed(String errorMessage) { + try { + log.complain(errorMessage); + log.complain("Stop execution"); + } finally { + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + + /* + * Print error message and exit with fail status + */ + static protected void exitAsFailed(Throwable t) { + try { + log.complain("Unexpected exception was thrown during TargetApplication execution: " + t); + t.printStackTrace(log.getOutStream()); + log.display("Stop execution"); + } finally { + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + + /* + * Following 3 methods can be overridden in subclasses: + * + * - init(String[] args) + * + * - targetApplicationActions() + * + * - afterAgentsFinished() + */ + + /* + * Test-specific initialization + */ + protected void init(String[] args) { + + } + + protected void targetApplicationActions() throws Throwable { + // do nothing by default + } + + protected void afterAgentsFinished() { + // do nothing by default + } + + public final void runTargetApplication(String[] args) { + initTargetApplication(args); + + SocketIOPipe pipe = null; + + try { + if (argParser.getPort() > 0) { + /* + * When target application initialized send signal to AODTestRunner + */ + pipe = SocketIOPipe.createClientIOPipe(log, "localhost", argParser.getPort(), 0); + log.display("Sending signal '" + AODTestRunner.SIGNAL_READY_FOR_ATTACH + "'"); + pipe.println(AODTestRunner.SIGNAL_READY_FOR_ATTACH); + } + + log.display("Waiting for agents connection"); + waitAgentsConnection(); + log.display("All expected agents connected"); + + try { + targetApplicationActions(); + } catch (Throwable e) { + /* + * If something goes wrong during test execution it is better + * to exit without waiting for agents + */ + + if (pipe != null) + pipe.close(); + + exitAsFailed(e); + } + + log.display("Waiting for agents finishing"); + waitAgentsFinishing(); + log.display("All agents finished execution"); + + afterAgentsFinished(); + + if (pipe != null) { + /* + * Don't finish execution until AODTestRunner attached agents + */ + String signal = pipe.readln(); + log.display("Signal received: '" + signal + "'"); + if ((signal == null) || !signal.equals(AODTestRunner.SIGNAL_FINISH)) + throw new TestBug("Unexpected AODTestRunner signal: '" + signal + "'"); + + if (testFailed) { + if (pipe != null) + pipe.close(); + + exitAsFailed("Error happened during TargetApplication execution (see error messages for details)"); + } else { + log.display("Test passed"); + } + } + } finally { + if (pipe != null) + pipe.close(); + } + } + + public static void main(String[] args) { + new TargetApplicationWaitingAgents().runTargetApplication(args); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/Utils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/Utils.java new file mode 100644 index 00000000000..8febc17e6de --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/Utils.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.aod; + +import java.io.File; + +import nsk.share.*; + +public class Utils { + + // prevent class instantiation + private Utils() { + } + + public static final long JPS_WORK_TIMEOUT = 60000; // 1 min + + /** + * Find id of VM with certain value of property key. Method findVMIdUsingJPS + * runs 'jps -v' and seeks in jps output line containing this unique string, + * discovered string should also contain VM id. + * + * @param jdkPath - path to jdk + * @param key - name of property + * @param value - value of property + * @return VM id + */ + public static String findVMIdUsingJPS(String jdkPath, String key, String value) { + try { + if (value == null) { + return null; + } + String idString = key + "=" + value; + String jpsPath = jdkPath + File.separator + "bin" + File.separator + "jps"; + + while (true) { + ProcessExecutor executor = new ProcessExecutor(jpsPath + " -v", JPS_WORK_TIMEOUT, "jps -v"); + executor.startProcess(); + executor.waitForProcess(); + + if (executor.getExitCode() != 0) { + throw new Failure("jps finished with non-zero code " + executor.getExitCode()); + } + + for (String jpsOutLine : executor.getProcessOut()) { + if (jpsOutLine.contains(idString)) { + if (jpsOutLine.indexOf(' ') < 0) + throw new Failure("Unexpected format of the jps output '" + jpsOutLine + " (line doesn't contain space)"); + + return jpsOutLine.substring(0, jpsOutLine.indexOf(' ')); + } + } + Thread.sleep(100); + } + } catch (Failure f) { + throw f; + } catch (Throwable t) { + throw new Failure("Unexpected exception during jps execution: " + t, t); + } + } + + public static String findCurrentVMIdUsingJPS(String jdkPath) { + /* + * VM should be run with special property which allows to find VM id using jps + * (see comments for method Utils.findVMIdUsingJPS) + */ + String applicationId = System.getProperty(AODTestRunner.targetAppIdProperty); + if (applicationId == null) + throw new TestBug("Property '" + AODTestRunner.targetAppIdProperty + "' isn't defined"); + + String targetVMId = Utils.findVMIdUsingJPS(jdkPath, AODTestRunner.targetAppIdProperty, applicationId); + + return targetVMId; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.c b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.c new file mode 100644 index 00000000000..6956ce55516 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static volatile int internalError = 0; + +/* + * This function can be used to inform AOD framework that some non critical for test logic + * error happened inside shared function (e.g. JVMTI Deallocate failed). + * + * If this function was called status of all finishing AOD agents is changed to failed. + */ + +void nsk_aod_internal_error() { + NSK_COMPLAIN0("WARNING: some error happened inside common function, see log for details\n"); + internalError = 1; +} + +void nsk_free_options(Options* options) { + if (options != NULL) { + int i; + for (i = 0; i < NSK_AOD_MAX_OPTIONS; i++) { + if (options->names[i] != NULL) { + free(options->names[i]); + } + if (options->values[i] != NULL) { + free(options->values[i]); + } + } + free(options); + } +} +/* + * Work with agent options + */ + +/* + * Parse options and create structure Options + */ +static Options* nsk_aod_createOptionsObject(char* optionsString) { + int i = 0; + Options* options; + char* name; + char* value; + char* sep; + + if (optionsString == NULL) { + NSK_COMPLAIN0("options were not passed to the native agent\n"); + return NULL; + } + options = (Options*) malloc(sizeof(Options)); + memset(options, 0, sizeof(Options)); + options->size = 0; + name = optionsString; + while (name != NULL && i < NSK_AOD_MAX_OPTIONS) { + sep = strchr(name, '='); + if (sep == NULL) { // name not found + NSK_COMPLAIN1("Invalid options format: '%s'\n", optionsString); + nsk_free_options(options); + return NULL; + } + *sep = '\0'; + options->names[i] = strdup(name); + value = sep + 1; + if (*value == '\0') { // value not found + NSK_COMPLAIN1("Option '%s' is empty\n", options->names[i]); + nsk_free_options(options); + return NULL; + } + sep = strchr(value, ' '); + if (sep != NULL) { + *sep = '\0'; + name = sep + 1; + } else { + name = strchr(value, '\0'); + } + options->values[i] = strdup(value); + i++; + + if (*name == '\0') { + name = NULL; + } + } + if (name != NULL) { + NSK_COMPLAIN1("WARNING: not all options were parsed, only %d options can be specified\n", + NSK_AOD_MAX_OPTIONS); + } + options->size = i; + return options; +} + +Options* nsk_aod_createOptions(char* optionsString) { + Options* options; + + if (!NSK_VERIFY((options = (Options*) nsk_aod_createOptionsObject(optionsString)) != NULL)) + return NULL; + + if (!NSK_VERIFY(nsk_aod_optionSpecified(options, NSK_AOD_AGENT_NAME_OPTION))) { + NSK_COMPLAIN0("Agent name wasn't specified\n"); + return NULL; + } + + /* + * verbose mode is true by default + */ + nsk_setVerboseMode(NSK_TRUE); + + if (nsk_aod_optionSpecified(options, NSK_AOD_VERBOSE_OPTION)) { + if (strcmp(nsk_aod_getOptionValue(options, NSK_AOD_VERBOSE_OPTION), "false") == 0) + nsk_setVerboseMode(NSK_FALSE); + } + + return options; +} + +const char* nsk_aod_getOptionValue(Options* options, const char* option) { + int i; + + if (!NSK_VERIFY(options != NULL)) { + NSK_COMPLAIN0("Options NULL\n"); + return NULL; + } + + for(i = 0; i < options->size; i++) { + if (strcmp(option, options->names[i]) == 0) { + return options->values[i]; + } + } + + NSK_COMPLAIN1("Option '%s' isn't defined\n", option); + + return NULL; +} + +int nsk_aod_optionSpecified(Options* options, const char* option) { + int i; + + if (!NSK_VERIFY(options != NULL)) { + NSK_COMPLAIN0("Options NULL\n"); + return NSK_FALSE; + } + + for(i = 0; i < options->size; i++) { + if (strcmp(option, options->names[i]) == 0) { + return NSK_TRUE; + } + } + + return NSK_FALSE; +} + +/* + * Agent synchronization with target application + */ + +static const char* TARGET_APP_CLASS_NAME = "nsk/share/aod/TargetApplicationWaitingAgents"; + +static const char* AGENT_LOADED_METHOD_NAME = "agentLoaded"; +static const char* AGENT_LOADED_METHOD_SIGNATURE = "(Ljava/lang/String;)V"; + +static const char* AGENT_FINISHED_METHOD_NAME = "agentFinished"; +static const char* AGENT_FINISHED_METHOD_SIGNATURE = "(Ljava/lang/String;Z)V"; + +static jclass targetAppClass = NULL; +static jmethodID agentLoadedMethod = NULL; +static jmethodID agentFinishedMethod = NULL; + +// this function is used to notify target application that native agent has been loaded +int nsk_aod_agentLoaded(JNIEnv* jni, const char* agentName) { + jstring agentNameString; + + NSK_DISPLAY1("Agent %s is loaded\n", agentName); + + if (targetAppClass == NULL) { + /* + * FindClass returns local reference, to cache reference to target application class + * global reference should be created + */ + jclass localTargetAppClass; + if (!NSK_JNI_VERIFY(jni, (localTargetAppClass = + NSK_CPP_STUB2(FindClass, jni, TARGET_APP_CLASS_NAME)) != NULL)) { + return NSK_FALSE; + } + + if (!NSK_JNI_VERIFY(jni, (targetAppClass = + NSK_CPP_STUB2(NewGlobalRef, jni, localTargetAppClass)) != NULL)) { + return NSK_FALSE; + } + } + + if (agentLoadedMethod == NULL) { + if (!NSK_JNI_VERIFY(jni, (agentLoadedMethod = + NSK_CPP_STUB4(GetStaticMethodID, jni, targetAppClass, + AGENT_LOADED_METHOD_NAME, AGENT_LOADED_METHOD_SIGNATURE)) != NULL)) + return NSK_FALSE; + } + + if (!NSK_JNI_VERIFY(jni, (agentNameString = + NSK_CPP_STUB2(NewStringUTF, jni, agentName)) != NULL)) + return NSK_FALSE; + + NSK_CPP_STUB4(CallStaticVoidMethod, jni, targetAppClass, agentLoadedMethod, agentNameString); + + return NSK_TRUE; +} + +// this function is used to notify target application that native agent has been finished execution +int nsk_aod_agentFinished(JNIEnv* jni, const char* agentName, int success) { + jstring agentNameString; + + if (!targetAppClass) { + NSK_COMPLAIN1("%s: TEST LOGIC ERROR: method 'agentFinished' was called before "\ + "targetAppClass was initialized\n", agentName); + return NSK_FALSE; + } + + if (internalError && success) { + success = 0; + NSK_COMPLAIN1("Status of agent '%s' is 'passed', but some error happened during test execution "\ + "(see log for details), change agent status to 'failed'\n", + agentName); + } + + NSK_DISPLAY2("Agent %s finished (success: %d)\n", agentName, success); + + if (agentFinishedMethod == NULL) { + if (!NSK_JNI_VERIFY(jni, (agentFinishedMethod = + NSK_CPP_STUB4(GetStaticMethodID, jni, targetAppClass, + AGENT_FINISHED_METHOD_NAME, AGENT_FINISHED_METHOD_SIGNATURE)) != NULL)) + return NSK_FALSE; + } + + if (!NSK_JNI_VERIFY(jni, (agentNameString = NSK_CPP_STUB2(NewStringUTF, jni, agentName)) != NULL)) + return NSK_FALSE; + + NSK_CPP_STUB5(CallStaticVoidMethod, jni, targetAppClass, + agentFinishedMethod, agentNameString, success ? JNI_TRUE : JNI_FALSE); + + return NSK_TRUE; +} + +/* + * Auxiliary functions + */ + +// JNI env creation + +JNIEnv* nsk_aod_createJNIEnv(JavaVM* vm) { + JNIEnv* jni; + NSK_CPP_STUB3(GetEnv, vm, (void**)&jni, JNI_VERSION_1_2); + + NSK_VERIFY(jni != NULL); + + return jni; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.h b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.h new file mode 100644 index 00000000000..a6bb112645e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#ifndef NSK_SHARE_AOD_H +#define NSK_SHARE_AOD_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This function can be used to inform AOD framework that some non-critical for test logic + * error happened inside shared function (e.g. JVMTI Deallocate failed). + * + * If this function was called status of all finishing AOD agents is changed to failed. + */ + +void nsk_aod_internal_error(); + +/* + * Work with agent options + */ + +#define NSK_AOD_MAX_OPTIONS 10 + +#define NSK_AOD_AGENT_NAME_OPTION "-agentName" +#define NSK_AOD_VERBOSE_OPTION "-verbose" + +typedef struct { + char* names[NSK_AOD_MAX_OPTIONS]; + char* values[NSK_AOD_MAX_OPTIONS]; + int size; +} Options; + +Options* nsk_aod_createOptions(char* optionsString); + +const char* nsk_aod_getOptionValue(Options* options, const char* option); + +int nsk_aod_optionSpecified(Options* options, const char* option); + +/* + * Agent synchronization with target application + */ + +// this function is used to notify target application that native agent has been loaded +int nsk_aod_agentLoaded(JNIEnv* jni, const char* agentName); + +// this function is used to notify target application that native agent has been finished execution +int nsk_aod_agentFinished(JNIEnv* jni, const char* agentName, int success); + + +// JNI env creation + +JNIEnv* nsk_aod_createJNIEnv(JavaVM* vm); + +#ifdef __cplusplus +} +#endif + +#endif /* END OF NSK_SHARE_AOD_H */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/classload/ClassPathNonDelegatingClassLoader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/ClassPathNonDelegatingClassLoader.java new file mode 100644 index 00000000000..b99a91dfad2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/ClassPathNonDelegatingClassLoader.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.classload; + +import java.io.*; +import java.util.*; + +import nsk.share.FileUtils; + +/** + * Custom classloader that does not delegate to it's parent. + * + * It can load classes from classpath that have name containing + * "Class" (any package). + */ +public class ClassPathNonDelegatingClassLoader extends ClassLoader { + private String [] classPath; + + public ClassPathNonDelegatingClassLoader() { + classPath = System.getProperty("java.class.path").split(File.pathSeparator); + } + + public synchronized Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + Class c = findLoadedClass(name); + if (c != null) { + System.out.println("Found class: " + name); + return c; + } + if (name.contains("Class")) { + String newName = name.replace('.', '/'); + return loadClassFromFile(name, newName + ".class", resolve); + } else { + return findSystemClass(name); + } + } + + private Class loadClassFromFile(String name, String fname, boolean resolve) + throws ClassNotFoundException { + try { + File target = new File(""); + + for(int i = 0; i < classPath.length; ++i) { + target = new File(classPath[i] + File.separator + fname); + if (target.exists()) + break; + } + if (!target.exists()) + throw new java.io.FileNotFoundException(); + byte[] buffer = FileUtils.readFile(target); + Class c = defineClass(name, buffer, 0, buffer.length); + if (resolve) + resolveClass(c); + return c; + } catch (IOException e) { + throw new ClassNotFoundException("Exception while reading classfile data", e); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java new file mode 100644 index 00000000000..37215400e97 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.classload; + +import java.io.*; +import java.util.*; +import nsk.share.*; + +/** + * Classloader that generates classes on the fly. + * + * This classloader can load classes with name starting with 'Class'. + * It will use nsk.share.classload.TemplateClass as template and will + * replace class name in the bytecode of template class. It can be used + * for example to detect memory leaks in class loading or to quickly + * fill PermGen. + */ +public class GeneratingClassLoader extends ClassLoader { + public static final String DEFAULT_CLASSNAME = TemplateClass.class.getName(); + public static final String PREFIX = "Class"; + + private final String [] classPath; + private byte[] bytecode; + private int[] offsets; + private final String encoding = "UTF8"; + private final String templateClassName; + private final byte[] templateClassNameBytes; + + /** + * Create generating class loader that will use class file + * for given class from classpath as template. + */ + public GeneratingClassLoader(String templateClassName) { + this.templateClassName = templateClassName; + classPath = System.getProperty("java.class.path").split(File.pathSeparator); + try { + templateClassNameBytes = templateClassName.getBytes(encoding); + } catch (UnsupportedEncodingException e) { + throw new TestBug(e); + } + } + + /** + * Create generating class loader that will use class file + * for nsk.share.classload.TemplateClass as template. + */ + public GeneratingClassLoader() { + this("nsk.share.classload.TemplateClass"); + } + + public int getNameLength() { + return templateClassName.length(); + } + + public String getPrefix() { + return PREFIX; + } + + public String getClassName(int number) { + StringBuffer sb = new StringBuffer(); + sb.append(PREFIX); + sb.append(number); + int n = templateClassName.length() - sb.length(); + for (int i = 0; i < n; ++i) + sb.append("_"); + return sb.toString(); + } + + public synchronized Class loadClass(String name) throws ClassNotFoundException { + return loadClass(name, false); + } + + public synchronized Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + Class c = findLoadedClass(name); + if (c != null) + return c; + if (!name.startsWith(PREFIX)) + return super.loadClass(name, resolve); + if (name.length() != templateClassName.length()) + throw new ClassNotFoundException("Only can load classes with name.length() = " + getNameLength() + " got: '" + name + "' length: " + name.length()); + byte[] bytecode = getPatchedByteCode(name); + c = defineClass(name, bytecode, 0, bytecode.length); + if (resolve) + resolveClass(c); + return c; + } + + private byte[] getPatchedByteCode(String name) throws ClassNotFoundException { + try { + byte[] bytecode = getByteCode(); + String fname = name.replace(".", File.separator); + byte[] replaceBytes = fname.getBytes(encoding); + for (int offset : offsets) { + for (int i = 0; i < replaceBytes.length; ++i) + bytecode[offset + i] = replaceBytes[i]; + } + return bytecode; + } catch (UnsupportedEncodingException e) { + throw new TestBug(e); + } catch (IOException e) { + throw new TestBug(e); + } + } + + private byte[] getByteCode() throws ClassNotFoundException { + if (bytecode == null) + readByteCode(); + if (offsets == null) { + getOffsets(bytecode); + if (offsets == null) + throw new TestBug("Class name not found in template class file"); + } + return (byte[]) bytecode.clone(); + } + + private void readByteCode() throws ClassNotFoundException { + String fname = templateClassName.replace(".", File.separator) + ".class"; + File target = null; + for (int i = 0; i < classPath.length; ++i) { + target = new File(classPath[i] + File.separator + fname); + if (target.exists()) + break; + } + + if (target == null || !target.exists()) + throw new ClassNotFoundException("File not found: " + target); + try { + bytecode = FileUtils.readFile(target); + } catch (IOException e) { + throw new ClassNotFoundException(templateClassName, e); + } + } + + private void getOffsets(byte[] bytecode) { + List offsets = new ArrayList(); + if (this.offsets == null) { + String pname = templateClassName.replace(".", "/"); + try { + byte[] pnameb = pname.getBytes(encoding); + int i = 0; + while (true) { + while (i < bytecode.length) { + int j = 0; + while (j < pnameb.length && bytecode[i + j] == pnameb[j]) + ++j; + if (j == pnameb.length) + break; + i++; + } + if (i == bytecode.length) + break; + offsets.add(new Integer(i)); + i++; + } + } catch (UnsupportedEncodingException e) { + throw new TestBug(e); + } + this.offsets = new int[offsets.size()]; + for (int i = 0; i < offsets.size(); ++i) + this.offsets[i] = offsets.get(i).intValue(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/classload/TemplateClass.java b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/TemplateClass.java new file mode 100644 index 00000000000..d967c2e313c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/TemplateClass.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.classload; + +public class TemplateClass { +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Algorithms.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Algorithms.java new file mode 100644 index 00000000000..404dc6498f7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Algorithms.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import java.io.*; +import java.util.*; +import nsk.share.*; +import nsk.share.gc.gp.*; +import nsk.share.test.ExecutionController; + +/** + * Algorithms class collects main algorithms that are used in + * GC testing. + */ +public class Algorithms { + /** Number of threads that one CPU can manage. */ + public final static long THREADS_MANAGED_BY_ONE_CPU = 100; + + /** Number of threads that one block of memory can manage. */ + public final static long THREADS_MANAGED_BY_ONE_BLOCK = 200; + + /** Default maximum number of elements in array. */ + public final static int MAX_ARRAY_SIZE = 65535; + + // Block of memory is 64M + private final static long BLOCK_SIZE = 64 * 1024 * 1024; // 64M + + // Minimal memory chunk size to eat + private final static int MIN_MEMORY_CHUNK = 512; // Bytes + + // Number of attempts to print a string. Print may fail because of + // OutOfMemoryError, so this constat specifies the number of attemts + // to print despite of OOME. + private final static int ATTEMPTS_TO_PRINT = 3; + + // This object stores any Failure that is thrown in Gourmand class + // and used in eatMemory(int) method + private static Failure failure = null; + + // This object is intended for wait() + private static Object object = new Object(); + + /** + * Default constructor. + */ + private Algorithms() {} + + /** + * Stresses memory by allocating arrays of bytes. The method allocates + * objects in the same thread and does not invoke GC explicitly by + * calling System.gc(). + *

      + * + * Note that this method can throw Failure if any exception + * is thrown while eating memory. To avoid OOM while allocating + * exception we preallocate it before the lunch starts. It means + * that exception stack trace does not correspond to the place + * where exception is thrown, but points at start of the method. + * + * This method uses nsk.share.test.Stresser class to control + * it's execution. Consumed number of iterations depends on + * available memory. + * + * @throws nsk.share.Failure if any unexpected exception is + * thrown during allocating of the objects. + * + * @see nsk.share.test.Stresser + */ + public static void eatMemory(ExecutionController stresser) { + GarbageUtils.eatMemory(stresser, 50, MIN_MEMORY_CHUNK, 2); + } + + /** + * Calculates and returns recomended number of threads to start in the + * particular machine (with particular amount of memory and number of CPUs). + * The returned value is minimum of two values: + * {@link #THREADS_MANAGED_BY_ONE_CPU} * (number of processors) and + * {@link #THREADS_MANAGED_BY_ONE_BLOCK} * (number of blocks of the memory). + * + * @return recomended number of threads to start. + * + */ + public static int getThreadsCount() { + Runtime runtime = Runtime.getRuntime(); + int processors = runtime.availableProcessors(); + long maxMemory = runtime.maxMemory(); + long blocks = Math.round((double) maxMemory / BLOCK_SIZE); + + return (int) Math.min(THREADS_MANAGED_BY_ONE_CPU * processors, + THREADS_MANAGED_BY_ONE_BLOCK * blocks); + } + + /** + * Returns the number of processors available to the Java virtual machine. + * + * @return number of processors available to the Java virtual machine. + * + * @see Runtime#availableProcessors + * + */ + public static int availableProcessors() { + Runtime runtime = Runtime.getRuntime(); + return runtime.availableProcessors(); + } + + /** + * Makes a few attempts to print the string into specified PrintStream. + * If PrintStream.println(String) throws OutOfMemoryError, + * the method waits for a few milliseconds and repeats the attempt. + * + * @param out PrintStream to print the string. + * @param s the string to print. + */ + public static void tryToPrintln(PrintStream out, String s) { + for (int i = 0; i < ATTEMPTS_TO_PRINT; i++) { + try { + out.println(s); + + // The string is printed into the PrintStream + return; + } catch (OutOfMemoryError e) { + + // Catch the error and wait for a while + synchronized(object) { + try { + object.wait(500); + } catch (InterruptedException ie) { + + // Ignore the exception + } + } // synchronized + } + } + } // tryToPrintln() + + /** + * Makes a few attempts to print each stack trace of Throwable + * into specified PrintStream. If PrintStream.println(String) + * throws OutOfMemoryError, the method waits for a few milliseconds and + * repeats the attempt. + * + * @param out PrintStream to print the string. + * @param t the throwable to print. + * + * @see #tryToPrintln + */ + public static void tryToPrintStack(PrintStream out, Throwable t) { + StackTraceElement[] trace = t.getStackTrace(); + + for (int i = 0; i < trace.length; i++) { + for (int j = 0; j < ATTEMPTS_TO_PRINT; j++) { + try { + out.println(trace[i].toString()); + + // The string is printed into the PrintStream + return; + } catch (OutOfMemoryError e) { + + // Catch the error and wait for a while + synchronized(object) { + try { + object.wait(500); + } catch (InterruptedException ie) { + + // Ignore the exception + } + } // synchronized + } // try + } // for j + } // for i + } // tryToPrintStack() + + /** + * Returns recommended size for an array. Default implemetation returns + * minimum between size and + * {@link #MAX_ARRAY_SIZE MAX_ARRAY_SIZE}. + * + * @return recommended size for an array. + * + */ + public static int getArraySize(long size) { + long min = Math.min(MAX_ARRAY_SIZE, size); + return (int) min; + } // getArraySize() +} // class Algorithms diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllDiag.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllDiag.java new file mode 100644 index 00000000000..e9f9b42955e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllDiag.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.runner.RunParams; + +/** + * Helper that prints information about AllMemoryObjects. + */ +public class AllDiag implements Runnable { + private long sleepTime; + + public AllDiag() { + this(RunParams.getInstance().getSleepTime()); + } + + public AllDiag(long sleepTime) { + this.sleepTime = sleepTime; + } + + public void run() { + AllMemoryObject.dumpStatistics(); + // Ensure that interrupt status is not lost + if (Thread.currentThread().isInterrupted()) + return; + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllMemoryObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllMemoryObject.java new file mode 100644 index 00000000000..cc0ad91b6ad --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllMemoryObject.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import java.io.PrintStream; + +/** + * An object that occupies approximately given number of bytes in memory + * and also records number of allocated instances. + */ +public class AllMemoryObject extends MemoryObject { + private static int allocatedCount; + + public AllMemoryObject(int size) { + super(size); + synchronized (AllMemoryObject.class) { + ++allocatedCount; + } + } + + /** + * Returns the number of allocated FinMemoryObjects. + */ + public static int getAllocatedCount() { + return allocatedCount; + } + + public static void dumpStatistics(PrintStream out) { + out.println("Object count: " + getAllocatedCount()); + } + + public static void dumpStatistics() { + dumpStatistics(System.out); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ArgumentHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ArgumentHandler.java new file mode 100644 index 00000000000..f9d56730de1 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ArgumentHandler.java @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.*; + +/** + * Parser for GC tests' arguments. + *

      + * ArgumentHandler handles specific command line arguments + * related to way of execution of a test in addition to general arguments + * recognized by {@link ArgumentParser ArgumentParser}. + *

      + * Following is the list of specific options for ArgumentHandler: + *

        + *
      • -iterations="value", where value must either + * be "infinity", or an integer number, greater than 0. This parameter + * specifies the number of iterations to run the testcase. If the value is + * "infinity", then the test will be run for at least gcTimeout + * minutes. Otherwise, the testcase will be repeated for + * iterations times. + *
      • -gcTimeout="value", where value must be an + * integer number, greater than 0. If infinity is set to + * iterations, then the test consider gcTimeout + * argument to run the test for at least specified number of minutes. + *
      • -threads="value", where value must be an + * integer number, greater than 0. A user may specify the number of threads + * to start in the test with that paramenter. However, a test may ignore + * this value, if it does know the number of threads to start. It + * depends on a test: read its README file. + *
      • -memoryEater="value", where value must be + * either "single", or "multi" string. This argument specifies if a single + * thread should be used to eat the whole heap or not. If "multi" string is + * assigned to -memoryEater, then a number of threads will be + * started to eat the heap. The number is equal to number of available + * processors plus 1. + *
      • -largeClassesPath="value", where value is a + * directory to load large classes from. + *
      • -fieldsLimitation="value", where value must + * be either "over", or "under" string. This argument specifies what classes + * should be loaded from largeClassesPath directory. If + * over is set, then the classes that have number of fileds over + * JVM limitation should be loaded, otherwise -- classes that have number + * of fileds under limitation. + *
      + * @see ArgumentParser + */ +public class ArgumentHandler extends ArgumentParser { + + // Define all possible arguments + private final static String ITERATIONS = "iterations"; + private final static String AGGREGATION_DEPTH = "aggregationDepth"; + private final static String GC_TIMEOUT = "gcTimeout"; + private final static String THREADS = "threads"; + private final static String MEM_EATER = "memoryEater"; + private final static String LARGE_CLASSES_PATH = "largeClassesPath"; + private final static String FIELDS_LIMITATION = "fieldsLimitation"; + + // An acceptible value for ITERATIONS + private final static String INFINITY = "infinity"; + + // Acceptible values for MEM_EATER + private final static String ME_SINGLE = "single"; + private final static String ME_MULTI = "multi"; + + // Acceptible values for FIELDS_LIMITATION + private final static String FL_OVER = "over"; + private final static String FL_UNDER = "under"; + + /** + * Keep a copy of raw command-line arguments and parse them; + * but throw an exception on parsing error. + * + * @param args Array of the raw command-line arguments. + * + * @throws BadOption If unknown option or illegal option value found + * + * @see ArgumentParser + */ + public ArgumentHandler(String args[]) { + super(args); + } + + /** + * Returns number of iterations. + *

      + * If -iterations="infinity", the method returns -1. + * If the argument is not set, the method returns 1. Otherwise, the + * specified number is returned. + * + * @return number of iterations. + * + */ + public int getIterations() { + String value = options.getProperty(ITERATIONS, "1"); + + if (INFINITY.equals(value)) + return -1; + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not an integer value of \"" + ITERATIONS + + "\" argument: " + value); + } + } + + + /** + * Returns the depth of object aggregation. + *

      + * If the argument is not set, the method returns 0. Otherwise, the + * specified number is returned. + * + * @return number of aggregation depth. + * + */ + public int getAggregationDepth() { + String value = options.getProperty(AGGREGATION_DEPTH, "0"); + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not an integer value of \"" + AGGREGATION_DEPTH + + "\" argument: " + value); + } + } + + + /** + * Returns number of minutes to run the test. + *

      + * @return number of minutes to run the test. + * + */ + public int getGCTimeout() { + String value = options.getProperty(GC_TIMEOUT); + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("\"" + GC_TIMEOUT + "\" argument is not defined " + + "or is not integer: " + value); + } + } + + /** + * Returns a directory to load large classes from. + *

      + * @return a directory to load large classes from. + * + */ + public String getLargeClassesPath() { + return options.getProperty(LARGE_CLASSES_PATH); + } + + /** + * Returns number of threads to start in a test. If threads + * is not set, the method returns specified number of threads. + *

      + * @param defaultValue default value, if threads is not set. + * @return number of threads to start in a test. + * + */ + public int getThreads(int defaultValue) { + String value = options.getProperty(THREADS); + + if (value == null) + return defaultValue; + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not an integer value of \"" + THREADS + + "\" argument: " + value); + } + } + + /** + * Returns true if single thread should be used to eat the whole heap, + * false otherwise. + * + * @return true if single thread should be used to eat the whole heap, + * false otherwise. + * + */ + public boolean isSingleMemoryEater() { + String value = options.getProperty(MEM_EATER); + + if (value == null) + return true; + else if (value.equals(ME_SINGLE)) + return true; + else if (value.equals(ME_MULTI)) + return false; + else + throw new TestBug("Value for \"" + MEM_EATER + "\" must be either " + + ME_SINGLE + ", or " + ME_MULTI); + } + + /** + * Returns true if classes with number of fileds over limitation should be + * loaded, false otherwise. + * + * @return true if classes with number of fileds over limitation should be + * loaded, false otherwise. + * + */ + public boolean isOverFieldsLimitation() { + String value = options.getProperty(FIELDS_LIMITATION); + + if (value == null) + return false; + else if (value.equals(FL_OVER)) + return true; + else if (value.equals(FL_UNDER)) + return false; + else + throw new TestBug("Value for \"" + FIELDS_LIMITATION + "\" must be " + + "either " + FL_OVER + ", or " + FL_UNDER); + } + + /** + * Checks if an option is allowed and has proper value. + * This method is invoked by parseArguments() + * + * @param option option name + * @param value string representation of value + * (could be an empty string too) + * null if this option has no value + * @return true if option is allowed and has proper value, + * false if option is not admissible + * + * @throws BadOption if option has an illegal value + * + * @see #parseArguments() + */ + protected boolean checkOption(String option, String value) { + + // Define iterations + if (option.equals(ITERATIONS)) { + if (INFINITY.equals(value)) + return true; + + try { + int number = Integer.parseInt(value); + + if (number < 1) + throw new BadOption(option + ": value must be greater than " + + "zero."); + } catch (NumberFormatException e) { + throw new BadOption("Value for option \"" + option + "\" must " + + "be integer or \"" + INFINITY + "\": " + + value); + } + return true; + } + + // Define timeout + if (option.equals(GC_TIMEOUT)) { + try { + int number = Integer.parseInt(value); + + if (number < 0) + throw new BadOption(option + ": value must be a positive " + + "integer"); + } catch (NumberFormatException e) { + throw new BadOption("Value for option \"" + option + "\" must " + + "be integer: " + value); + } + return true; + } + + // Define threads + if (option.equals(THREADS)) { + try { + int number = Integer.parseInt(value); + + if (number < 0) + throw new BadOption(option + ": value must be a positive " + + "integer"); + } catch (NumberFormatException e) { + throw new BadOption("Value for option \"" + option + "\" must " + + "be integer: " + value); + } + return true; + } + + // Define path to large classes + if (option.equals(LARGE_CLASSES_PATH)) + return true; + + // Define memory eater + if (option.equals(MEM_EATER)) { + if ( (ME_SINGLE.equals(value)) || (ME_MULTI.equals(value)) ) + return true; + else + throw new BadOption("Value for option \"" + option + "\" must " + + "be either " + ME_SINGLE + ", or " + + ME_MULTI + ": " + value); + } + + // Define fields limitation + if (option.equals(FIELDS_LIMITATION)) { + if ( (FL_OVER.equals(value)) || (FL_UNDER.equals(value)) ) + return true; + else + throw new BadOption("Value for option \"" + option + "\" must " + + "be either " + FL_OVER + ", or " + + FL_UNDER + ": " + value); + } + + // Define aggregationDepth + if (option.equals(AGGREGATION_DEPTH)) { + try { + int number = Integer.parseInt(value); + + if (number < 0) + throw new BadOption(option + ": value must be a positive " + + "integer"); + } catch (NumberFormatException e) { + throw new BadOption("Value for option \"" + option + "\" must " + + "be integer: " + value); + } + return true; + } + + return super.checkOption(option, value); + } + + /** + * Checks if the values of all options are consistent. + * This method is invoked by parseArguments() + * + * @throws BadOption if options have inconsistent values + * + * @see ArgumentParser#parseArguments() + */ + protected void checkOptions() { + super.checkOptions(); + } +} // ArgumentHandler diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Cell.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Cell.java new file mode 100644 index 00000000000..e2c65087111 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Cell.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.gc.MemoryObject; + +public class Cell extends MemoryObject { + private int number; + + public Cell(int size, int number) { + super(size - 4); + setNumber(number); + } + + public final int getNumber() { + return number; + } + + public final void setNumber(int number) { + this.number = number; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/CircularLinkedList.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/CircularLinkedList.java new file mode 100644 index 00000000000..48cdf041b1a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/CircularLinkedList.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +public class CircularLinkedList { + private int objectSize; + private LinkedMemoryObject root; + + /** + * Create empty circular linked list. + * + * @param objectSize size of each node in the list + */ + public CircularLinkedList(int objectSize) { + this.objectSize = objectSize; + } + + /** + * Insert new node in the list. + */ + public void grow() { + LinkedMemoryObject newnode = new LinkedMemoryObject(objectSize); + if (root == null){ + root = newnode; + root.setNext(root); + root.setPrev(root); + } else { + newnode.setNext(root.getNext()); + root.getNext().setPrev(newnode); + root.setNext(newnode); + newnode.setPrev(root); + } + } + + /** + * Get length of the list. + * + * @return length + */ + public int getLength() { + return Memory.getListLength(root); + } + + /** + * Get length of another list. + * + * @param list another list + * @return length of list + */ + public int getLength(CircularLinkedList list) { + return Memory.getListLength(list.root); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ClassChain.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ClassChain.java new file mode 100644 index 00000000000..1e73f340b1b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ClassChain.java @@ -0,0 +1,5035 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +/** + * Object with long dependency chain. + * + * Instantiation of this class forces loading of all classes Class*. + */ +public class ClassChain { + public ClassChain(){ + new Class1(); + } +} + +class Class1 { + public Class1(){ + new Class2(); + } +} +class Class2 { + public Class2(){ + new Class3(); + } +} +class Class3 { + public Class3(){ + new Class4(); + } +} +class Class4 { + public Class4(){ + new Class5(); + } +} +class Class5 { + public Class5(){ + new Class6(); + } +} +class Class6 { + public Class6(){ + new Class7(); + } +} +class Class7 { + public Class7(){ + new Class8(); + } +} +class Class8 { + public Class8(){ + new Class9(); + } +} +class Class9 { + public Class9(){ + new Class10(); + } +} +class Class10 { + public Class10(){ + new Class11(); + } +} +class Class11 { + public Class11(){ + new Class12(); + } +} +class Class12 { + public Class12(){ + new Class13(); + } +} +class Class13 { + public Class13(){ + new Class14(); + } +} +class Class14 { + public Class14(){ + new Class15(); + } +} +class Class15 { + public Class15(){ + new Class16(); + } +} +class Class16 { + public Class16(){ + new Class17(); + } +} +class Class17 { + public Class17(){ + new Class18(); + } +} +class Class18 { + public Class18(){ + new Class19(); + } +} +class Class19 { + public Class19(){ + new Class20(); + } +} +class Class20 { + public Class20(){ + new Class21(); + } +} +class Class21 { + public Class21(){ + new Class22(); + } +} +class Class22 { + public Class22(){ + new Class23(); + } +} +class Class23 { + public Class23(){ + new Class24(); + } +} +class Class24 { + public Class24(){ + new Class25(); + } +} +class Class25 { + public Class25(){ + new Class26(); + } +} +class Class26 { + public Class26(){ + new Class27(); + } +} +class Class27 { + public Class27(){ + new Class28(); + } +} +class Class28 { + public Class28(){ + new Class29(); + } +} +class Class29 { + public Class29(){ + new Class30(); + } +} +class Class30 { + public Class30(){ + new Class31(); + } +} +class Class31 { + public Class31(){ + new Class32(); + } +} +class Class32 { + public Class32(){ + new Class33(); + } +} +class Class33 { + public Class33(){ + new Class34(); + } +} +class Class34 { + public Class34(){ + new Class35(); + } +} +class Class35 { + public Class35(){ + new Class36(); + } +} +class Class36 { + public Class36(){ + new Class37(); + } +} +class Class37 { + public Class37(){ + new Class38(); + } +} +class Class38 { + public Class38(){ + new Class39(); + } +} +class Class39 { + public Class39(){ + new Class40(); + } +} +class Class40 { + public Class40(){ + new Class41(); + } +} +class Class41 { + public Class41(){ + new Class42(); + } +} +class Class42 { + public Class42(){ + new Class43(); + } +} +class Class43 { + public Class43(){ + new Class44(); + } +} +class Class44 { + public Class44(){ + new Class45(); + } +} +class Class45 { + public Class45(){ + new Class46(); + } +} +class Class46 { + public Class46(){ + new Class47(); + } +} +class Class47 { + public Class47(){ + new Class48(); + } +} +class Class48 { + public Class48(){ + new Class49(); + } +} +class Class49 { + public Class49(){ + new Class50(); + } +} +class Class50 { + public Class50(){ + new Class51(); + } +} +class Class51 { + public Class51(){ + new Class52(); + } +} +class Class52 { + public Class52(){ + new Class53(); + } +} +class Class53 { + public Class53(){ + new Class54(); + } +} +class Class54 { + public Class54(){ + new Class55(); + } +} +class Class55 { + public Class55(){ + new Class56(); + } +} +class Class56 { + public Class56(){ + new Class57(); + } +} +class Class57 { + public Class57(){ + new Class58(); + } +} +class Class58 { + public Class58(){ + new Class59(); + } +} +class Class59 { + public Class59(){ + new Class60(); + } +} +class Class60 { + public Class60(){ + new Class61(); + } +} +class Class61 { + public Class61(){ + new Class62(); + } +} +class Class62 { + public Class62(){ + new Class63(); + } +} +class Class63 { + public Class63(){ + new Class64(); + } +} +class Class64 { + public Class64(){ + new Class65(); + } +} +class Class65 { + public Class65(){ + new Class66(); + } +} +class Class66 { + public Class66(){ + new Class67(); + } +} +class Class67 { + public Class67(){ + new Class68(); + } +} +class Class68 { + public Class68(){ + new Class69(); + } +} +class Class69 { + public Class69(){ + new Class70(); + } +} +class Class70 { + public Class70(){ + new Class71(); + } +} +class Class71 { + public Class71(){ + new Class72(); + } +} +class Class72 { + public Class72(){ + new Class73(); + } +} +class Class73 { + public Class73(){ + new Class74(); + } +} +class Class74 { + public Class74(){ + new Class75(); + } +} +class Class75 { + public Class75(){ + new Class76(); + } +} +class Class76 { + public Class76(){ + new Class77(); + } +} +class Class77 { + public Class77(){ + new Class78(); + } +} +class Class78 { + public Class78(){ + new Class79(); + } +} +class Class79 { + public Class79(){ + new Class80(); + } +} +class Class80 { + public Class80(){ + new Class81(); + } +} +class Class81 { + public Class81(){ + new Class82(); + } +} +class Class82 { + public Class82(){ + new Class83(); + } +} +class Class83 { + public Class83(){ + new Class84(); + } +} +class Class84 { + public Class84(){ + new Class85(); + } +} +class Class85 { + public Class85(){ + new Class86(); + } +} +class Class86 { + public Class86(){ + new Class87(); + } +} +class Class87 { + public Class87(){ + new Class88(); + } +} +class Class88 { + public Class88(){ + new Class89(); + } +} +class Class89 { + public Class89(){ + new Class90(); + } +} +class Class90 { + public Class90(){ + new Class91(); + } +} +class Class91 { + public Class91(){ + new Class92(); + } +} +class Class92 { + public Class92(){ + new Class93(); + } +} +class Class93 { + public Class93(){ + new Class94(); + } +} +class Class94 { + public Class94(){ + new Class95(); + } +} +class Class95 { + public Class95(){ + new Class96(); + } +} +class Class96 { + public Class96(){ + new Class97(); + } +} +class Class97 { + public Class97(){ + new Class98(); + } +} +class Class98 { + public Class98(){ + new Class99(); + } +} +class Class99 { + public Class99(){ + new Class100(); + } +} +class Class100 { + public Class100(){ + new Class101(); + } +} +class Class101 { + public Class101(){ + new Class102(); + } +} +class Class102 { + public Class102(){ + new Class103(); + } +} +class Class103 { + public Class103(){ + new Class104(); + } +} +class Class104 { + public Class104(){ + new Class105(); + } +} +class Class105 { + public Class105(){ + new Class106(); + } +} +class Class106 { + public Class106(){ + new Class107(); + } +} +class Class107 { + public Class107(){ + new Class108(); + } +} +class Class108 { + public Class108(){ + new Class109(); + } +} +class Class109 { + public Class109(){ + new Class110(); + } +} +class Class110 { + public Class110(){ + new Class111(); + } +} +class Class111 { + public Class111(){ + new Class112(); + } +} +class Class112 { + public Class112(){ + new Class113(); + } +} +class Class113 { + public Class113(){ + new Class114(); + } +} +class Class114 { + public Class114(){ + new Class115(); + } +} +class Class115 { + public Class115(){ + new Class116(); + } +} +class Class116 { + public Class116(){ + new Class117(); + } +} +class Class117 { + public Class117(){ + new Class118(); + } +} +class Class118 { + public Class118(){ + new Class119(); + } +} +class Class119 { + public Class119(){ + new Class120(); + } +} +class Class120 { + public Class120(){ + new Class121(); + } +} +class Class121 { + public Class121(){ + new Class122(); + } +} +class Class122 { + public Class122(){ + new Class123(); + } +} +class Class123 { + public Class123(){ + new Class124(); + } +} +class Class124 { + public Class124(){ + new Class125(); + } +} +class Class125 { + public Class125(){ + new Class126(); + } +} +class Class126 { + public Class126(){ + new Class127(); + } +} +class Class127 { + public Class127(){ + new Class128(); + } +} +class Class128 { + public Class128(){ + new Class129(); + } +} +class Class129 { + public Class129(){ + new Class130(); + } +} +class Class130 { + public Class130(){ + new Class131(); + } +} +class Class131 { + public Class131(){ + new Class132(); + } +} +class Class132 { + public Class132(){ + new Class133(); + } +} +class Class133 { + public Class133(){ + new Class134(); + } +} +class Class134 { + public Class134(){ + new Class135(); + } +} +class Class135 { + public Class135(){ + new Class136(); + } +} +class Class136 { + public Class136(){ + new Class137(); + } +} +class Class137 { + public Class137(){ + new Class138(); + } +} +class Class138 { + public Class138(){ + new Class139(); + } +} +class Class139 { + public Class139(){ + new Class140(); + } +} +class Class140 { + public Class140(){ + new Class141(); + } +} +class Class141 { + public Class141(){ + new Class142(); + } +} +class Class142 { + public Class142(){ + new Class143(); + } +} +class Class143 { + public Class143(){ + new Class144(); + } +} +class Class144 { + public Class144(){ + new Class145(); + } +} +class Class145 { + public Class145(){ + new Class146(); + } +} +class Class146 { + public Class146(){ + new Class147(); + } +} +class Class147 { + public Class147(){ + new Class148(); + } +} +class Class148 { + public Class148(){ + new Class149(); + } +} +class Class149 { + public Class149(){ + new Class150(); + } +} +class Class150 { + public Class150(){ + new Class151(); + } +} +class Class151 { + public Class151(){ + new Class152(); + } +} +class Class152 { + public Class152(){ + new Class153(); + } +} +class Class153 { + public Class153(){ + new Class154(); + } +} +class Class154 { + public Class154(){ + new Class155(); + } +} +class Class155 { + public Class155(){ + new Class156(); + } +} +class Class156 { + public Class156(){ + new Class157(); + } +} +class Class157 { + public Class157(){ + new Class158(); + } +} +class Class158 { + public Class158(){ + new Class159(); + } +} +class Class159 { + public Class159(){ + new Class160(); + } +} +class Class160 { + public Class160(){ + new Class161(); + } +} +class Class161 { + public Class161(){ + new Class162(); + } +} +class Class162 { + public Class162(){ + new Class163(); + } +} +class Class163 { + public Class163(){ + new Class164(); + } +} +class Class164 { + public Class164(){ + new Class165(); + } +} +class Class165 { + public Class165(){ + new Class166(); + } +} +class Class166 { + public Class166(){ + new Class167(); + } +} +class Class167 { + public Class167(){ + new Class168(); + } +} +class Class168 { + public Class168(){ + new Class169(); + } +} +class Class169 { + public Class169(){ + new Class170(); + } +} +class Class170 { + public Class170(){ + new Class171(); + } +} +class Class171 { + public Class171(){ + new Class172(); + } +} +class Class172 { + public Class172(){ + new Class173(); + } +} +class Class173 { + public Class173(){ + new Class174(); + } +} +class Class174 { + public Class174(){ + new Class175(); + } +} +class Class175 { + public Class175(){ + new Class176(); + } +} +class Class176 { + public Class176(){ + new Class177(); + } +} +class Class177 { + public Class177(){ + new Class178(); + } +} +class Class178 { + public Class178(){ + new Class179(); + } +} +class Class179 { + public Class179(){ + new Class180(); + } +} +class Class180 { + public Class180(){ + new Class181(); + } +} +class Class181 { + public Class181(){ + new Class182(); + } +} +class Class182 { + public Class182(){ + new Class183(); + } +} +class Class183 { + public Class183(){ + new Class184(); + } +} +class Class184 { + public Class184(){ + new Class185(); + } +} +class Class185 { + public Class185(){ + new Class186(); + } +} +class Class186 { + public Class186(){ + new Class187(); + } +} +class Class187 { + public Class187(){ + new Class188(); + } +} +class Class188 { + public Class188(){ + new Class189(); + } +} +class Class189 { + public Class189(){ + new Class190(); + } +} +class Class190 { + public Class190(){ + new Class191(); + } +} +class Class191 { + public Class191(){ + new Class192(); + } +} +class Class192 { + public Class192(){ + new Class193(); + } +} +class Class193 { + public Class193(){ + new Class194(); + } +} +class Class194 { + public Class194(){ + new Class195(); + } +} +class Class195 { + public Class195(){ + new Class196(); + } +} +class Class196 { + public Class196(){ + new Class197(); + } +} +class Class197 { + public Class197(){ + new Class198(); + } +} +class Class198 { + public Class198(){ + new Class199(); + } +} +class Class199 { + public Class199(){ + new Class200(); + } +} +class Class200 { + public Class200(){ + new Class201(); + } +} +class Class201 { + public Class201(){ + new Class202(); + } +} +class Class202 { + public Class202(){ + new Class203(); + } +} +class Class203 { + public Class203(){ + new Class204(); + } +} +class Class204 { + public Class204(){ + new Class205(); + } +} +class Class205 { + public Class205(){ + new Class206(); + } +} +class Class206 { + public Class206(){ + new Class207(); + } +} +class Class207 { + public Class207(){ + new Class208(); + } +} +class Class208 { + public Class208(){ + new Class209(); + } +} +class Class209 { + public Class209(){ + new Class210(); + } +} +class Class210 { + public Class210(){ + new Class211(); + } +} +class Class211 { + public Class211(){ + new Class212(); + } +} +class Class212 { + public Class212(){ + new Class213(); + } +} +class Class213 { + public Class213(){ + new Class214(); + } +} +class Class214 { + public Class214(){ + new Class215(); + } +} +class Class215 { + public Class215(){ + new Class216(); + } +} +class Class216 { + public Class216(){ + new Class217(); + } +} +class Class217 { + public Class217(){ + new Class218(); + } +} +class Class218 { + public Class218(){ + new Class219(); + } +} +class Class219 { + public Class219(){ + new Class220(); + } +} +class Class220 { + public Class220(){ + new Class221(); + } +} +class Class221 { + public Class221(){ + new Class222(); + } +} +class Class222 { + public Class222(){ + new Class223(); + } +} +class Class223 { + public Class223(){ + new Class224(); + } +} +class Class224 { + public Class224(){ + new Class225(); + } +} +class Class225 { + public Class225(){ + new Class226(); + } +} +class Class226 { + public Class226(){ + new Class227(); + } +} +class Class227 { + public Class227(){ + new Class228(); + } +} +class Class228 { + public Class228(){ + new Class229(); + } +} +class Class229 { + public Class229(){ + new Class230(); + } +} +class Class230 { + public Class230(){ + new Class231(); + } +} +class Class231 { + public Class231(){ + new Class232(); + } +} +class Class232 { + public Class232(){ + new Class233(); + } +} +class Class233 { + public Class233(){ + new Class234(); + } +} +class Class234 { + public Class234(){ + new Class235(); + } +} +class Class235 { + public Class235(){ + new Class236(); + } +} +class Class236 { + public Class236(){ + new Class237(); + } +} +class Class237 { + public Class237(){ + new Class238(); + } +} +class Class238 { + public Class238(){ + new Class239(); + } +} +class Class239 { + public Class239(){ + new Class240(); + } +} +class Class240 { + public Class240(){ + new Class241(); + } +} +class Class241 { + public Class241(){ + new Class242(); + } +} +class Class242 { + public Class242(){ + new Class243(); + } +} +class Class243 { + public Class243(){ + new Class244(); + } +} +class Class244 { + public Class244(){ + new Class245(); + } +} +class Class245 { + public Class245(){ + new Class246(); + } +} +class Class246 { + public Class246(){ + new Class247(); + } +} +class Class247 { + public Class247(){ + new Class248(); + } +} +class Class248 { + public Class248(){ + new Class249(); + } +} +class Class249 { + public Class249(){ + new Class250(); + } +} +class Class250 { + public Class250(){ + new Class251(); + } +} +class Class251 { + public Class251(){ + new Class252(); + } +} +class Class252 { + public Class252(){ + new Class253(); + } +} +class Class253 { + public Class253(){ + new Class254(); + } +} +class Class254 { + public Class254(){ + new Class255(); + } +} +class Class255 { + public Class255(){ + new Class256(); + } +} +class Class256 { + public Class256(){ + new Class257(); + } +} +class Class257 { + public Class257(){ + new Class258(); + } +} +class Class258 { + public Class258(){ + new Class259(); + } +} +class Class259 { + public Class259(){ + new Class260(); + } +} +class Class260 { + public Class260(){ + new Class261(); + } +} +class Class261 { + public Class261(){ + new Class262(); + } +} +class Class262 { + public Class262(){ + new Class263(); + } +} +class Class263 { + public Class263(){ + new Class264(); + } +} +class Class264 { + public Class264(){ + new Class265(); + } +} +class Class265 { + public Class265(){ + new Class266(); + } +} +class Class266 { + public Class266(){ + new Class267(); + } +} +class Class267 { + public Class267(){ + new Class268(); + } +} +class Class268 { + public Class268(){ + new Class269(); + } +} +class Class269 { + public Class269(){ + new Class270(); + } +} +class Class270 { + public Class270(){ + new Class271(); + } +} +class Class271 { + public Class271(){ + new Class272(); + } +} +class Class272 { + public Class272(){ + new Class273(); + } +} +class Class273 { + public Class273(){ + new Class274(); + } +} +class Class274 { + public Class274(){ + new Class275(); + } +} +class Class275 { + public Class275(){ + new Class276(); + } +} +class Class276 { + public Class276(){ + new Class277(); + } +} +class Class277 { + public Class277(){ + new Class278(); + } +} +class Class278 { + public Class278(){ + new Class279(); + } +} +class Class279 { + public Class279(){ + new Class280(); + } +} +class Class280 { + public Class280(){ + new Class281(); + } +} +class Class281 { + public Class281(){ + new Class282(); + } +} +class Class282 { + public Class282(){ + new Class283(); + } +} +class Class283 { + public Class283(){ + new Class284(); + } +} +class Class284 { + public Class284(){ + new Class285(); + } +} +class Class285 { + public Class285(){ + new Class286(); + } +} +class Class286 { + public Class286(){ + new Class287(); + } +} +class Class287 { + public Class287(){ + new Class288(); + } +} +class Class288 { + public Class288(){ + new Class289(); + } +} +class Class289 { + public Class289(){ + new Class290(); + } +} +class Class290 { + public Class290(){ + new Class291(); + } +} +class Class291 { + public Class291(){ + new Class292(); + } +} +class Class292 { + public Class292(){ + new Class293(); + } +} +class Class293 { + public Class293(){ + new Class294(); + } +} +class Class294 { + public Class294(){ + new Class295(); + } +} +class Class295 { + public Class295(){ + new Class296(); + } +} +class Class296 { + public Class296(){ + new Class297(); + } +} +class Class297 { + public Class297(){ + new Class298(); + } +} +class Class298 { + public Class298(){ + new Class299(); + } +} +class Class299 { + public Class299(){ + new Class300(); + } +} +class Class300 { + public Class300(){ + new Class301(); + } +} +class Class301 { + public Class301(){ + new Class302(); + } +} +class Class302 { + public Class302(){ + new Class303(); + } +} +class Class303 { + public Class303(){ + new Class304(); + } +} +class Class304 { + public Class304(){ + new Class305(); + } +} +class Class305 { + public Class305(){ + new Class306(); + } +} +class Class306 { + public Class306(){ + new Class307(); + } +} +class Class307 { + public Class307(){ + new Class308(); + } +} +class Class308 { + public Class308(){ + new Class309(); + } +} +class Class309 { + public Class309(){ + new Class310(); + } +} +class Class310 { + public Class310(){ + new Class311(); + } +} +class Class311 { + public Class311(){ + new Class312(); + } +} +class Class312 { + public Class312(){ + new Class313(); + } +} +class Class313 { + public Class313(){ + new Class314(); + } +} +class Class314 { + public Class314(){ + new Class315(); + } +} +class Class315 { + public Class315(){ + new Class316(); + } +} +class Class316 { + public Class316(){ + new Class317(); + } +} +class Class317 { + public Class317(){ + new Class318(); + } +} +class Class318 { + public Class318(){ + new Class319(); + } +} +class Class319 { + public Class319(){ + new Class320(); + } +} +class Class320 { + public Class320(){ + new Class321(); + } +} +class Class321 { + public Class321(){ + new Class322(); + } +} +class Class322 { + public Class322(){ + new Class323(); + } +} +class Class323 { + public Class323(){ + new Class324(); + } +} +class Class324 { + public Class324(){ + new Class325(); + } +} +class Class325 { + public Class325(){ + new Class326(); + } +} +class Class326 { + public Class326(){ + new Class327(); + } +} +class Class327 { + public Class327(){ + new Class328(); + } +} +class Class328 { + public Class328(){ + new Class329(); + } +} +class Class329 { + public Class329(){ + new Class330(); + } +} +class Class330 { + public Class330(){ + new Class331(); + } +} +class Class331 { + public Class331(){ + new Class332(); + } +} +class Class332 { + public Class332(){ + new Class333(); + } +} +class Class333 { + public Class333(){ + new Class334(); + } +} +class Class334 { + public Class334(){ + new Class335(); + } +} +class Class335 { + public Class335(){ + new Class336(); + } +} +class Class336 { + public Class336(){ + new Class337(); + } +} +class Class337 { + public Class337(){ + new Class338(); + } +} +class Class338 { + public Class338(){ + new Class339(); + } +} +class Class339 { + public Class339(){ + new Class340(); + } +} +class Class340 { + public Class340(){ + new Class341(); + } +} +class Class341 { + public Class341(){ + new Class342(); + } +} +class Class342 { + public Class342(){ + new Class343(); + } +} +class Class343 { + public Class343(){ + new Class344(); + } +} +class Class344 { + public Class344(){ + new Class345(); + } +} +class Class345 { + public Class345(){ + new Class346(); + } +} +class Class346 { + public Class346(){ + new Class347(); + } +} +class Class347 { + public Class347(){ + new Class348(); + } +} +class Class348 { + public Class348(){ + new Class349(); + } +} +class Class349 { + public Class349(){ + new Class350(); + } +} +class Class350 { + public Class350(){ + new Class351(); + } +} +class Class351 { + public Class351(){ + new Class352(); + } +} +class Class352 { + public Class352(){ + new Class353(); + } +} +class Class353 { + public Class353(){ + new Class354(); + } +} +class Class354 { + public Class354(){ + new Class355(); + } +} +class Class355 { + public Class355(){ + new Class356(); + } +} +class Class356 { + public Class356(){ + new Class357(); + } +} +class Class357 { + public Class357(){ + new Class358(); + } +} +class Class358 { + public Class358(){ + new Class359(); + } +} +class Class359 { + public Class359(){ + new Class360(); + } +} +class Class360 { + public Class360(){ + new Class361(); + } +} +class Class361 { + public Class361(){ + new Class362(); + } +} +class Class362 { + public Class362(){ + new Class363(); + } +} +class Class363 { + public Class363(){ + new Class364(); + } +} +class Class364 { + public Class364(){ + new Class365(); + } +} +class Class365 { + public Class365(){ + new Class366(); + } +} +class Class366 { + public Class366(){ + new Class367(); + } +} +class Class367 { + public Class367(){ + new Class368(); + } +} +class Class368 { + public Class368(){ + new Class369(); + } +} +class Class369 { + public Class369(){ + new Class370(); + } +} +class Class370 { + public Class370(){ + new Class371(); + } +} +class Class371 { + public Class371(){ + new Class372(); + } +} +class Class372 { + public Class372(){ + new Class373(); + } +} +class Class373 { + public Class373(){ + new Class374(); + } +} +class Class374 { + public Class374(){ + new Class375(); + } +} +class Class375 { + public Class375(){ + new Class376(); + } +} +class Class376 { + public Class376(){ + new Class377(); + } +} +class Class377 { + public Class377(){ + new Class378(); + } +} +class Class378 { + public Class378(){ + new Class379(); + } +} +class Class379 { + public Class379(){ + new Class380(); + } +} +class Class380 { + public Class380(){ + new Class381(); + } +} +class Class381 { + public Class381(){ + new Class382(); + } +} +class Class382 { + public Class382(){ + new Class383(); + } +} +class Class383 { + public Class383(){ + new Class384(); + } +} +class Class384 { + public Class384(){ + new Class385(); + } +} +class Class385 { + public Class385(){ + new Class386(); + } +} +class Class386 { + public Class386(){ + new Class387(); + } +} +class Class387 { + public Class387(){ + new Class388(); + } +} +class Class388 { + public Class388(){ + new Class389(); + } +} +class Class389 { + public Class389(){ + new Class390(); + } +} +class Class390 { + public Class390(){ + new Class391(); + } +} +class Class391 { + public Class391(){ + new Class392(); + } +} +class Class392 { + public Class392(){ + new Class393(); + } +} +class Class393 { + public Class393(){ + new Class394(); + } +} +class Class394 { + public Class394(){ + new Class395(); + } +} +class Class395 { + public Class395(){ + new Class396(); + } +} +class Class396 { + public Class396(){ + new Class397(); + } +} +class Class397 { + public Class397(){ + new Class398(); + } +} +class Class398 { + public Class398(){ + new Class399(); + } +} +class Class399 { + public Class399(){ + new Class400(); + } +} +class Class400 { + public Class400(){ + new Class401(); + } +} +class Class401 { + public Class401(){ + new Class402(); + } +} +class Class402 { + public Class402(){ + new Class403(); + } +} +class Class403 { + public Class403(){ + new Class404(); + } +} +class Class404 { + public Class404(){ + new Class405(); + } +} +class Class405 { + public Class405(){ + new Class406(); + } +} +class Class406 { + public Class406(){ + new Class407(); + } +} +class Class407 { + public Class407(){ + new Class408(); + } +} +class Class408 { + public Class408(){ + new Class409(); + } +} +class Class409 { + public Class409(){ + new Class410(); + } +} +class Class410 { + public Class410(){ + new Class411(); + } +} +class Class411 { + public Class411(){ + new Class412(); + } +} +class Class412 { + public Class412(){ + new Class413(); + } +} +class Class413 { + public Class413(){ + new Class414(); + } +} +class Class414 { + public Class414(){ + new Class415(); + } +} +class Class415 { + public Class415(){ + new Class416(); + } +} +class Class416 { + public Class416(){ + new Class417(); + } +} +class Class417 { + public Class417(){ + new Class418(); + } +} +class Class418 { + public Class418(){ + new Class419(); + } +} +class Class419 { + public Class419(){ + new Class420(); + } +} +class Class420 { + public Class420(){ + new Class421(); + } +} +class Class421 { + public Class421(){ + new Class422(); + } +} +class Class422 { + public Class422(){ + new Class423(); + } +} +class Class423 { + public Class423(){ + new Class424(); + } +} +class Class424 { + public Class424(){ + new Class425(); + } +} +class Class425 { + public Class425(){ + new Class426(); + } +} +class Class426 { + public Class426(){ + new Class427(); + } +} +class Class427 { + public Class427(){ + new Class428(); + } +} +class Class428 { + public Class428(){ + new Class429(); + } +} +class Class429 { + public Class429(){ + new Class430(); + } +} +class Class430 { + public Class430(){ + new Class431(); + } +} +class Class431 { + public Class431(){ + new Class432(); + } +} +class Class432 { + public Class432(){ + new Class433(); + } +} +class Class433 { + public Class433(){ + new Class434(); + } +} +class Class434 { + public Class434(){ + new Class435(); + } +} +class Class435 { + public Class435(){ + new Class436(); + } +} +class Class436 { + public Class436(){ + new Class437(); + } +} +class Class437 { + public Class437(){ + new Class438(); + } +} +class Class438 { + public Class438(){ + new Class439(); + } +} +class Class439 { + public Class439(){ + new Class440(); + } +} +class Class440 { + public Class440(){ + new Class441(); + } +} +class Class441 { + public Class441(){ + new Class442(); + } +} +class Class442 { + public Class442(){ + new Class443(); + } +} +class Class443 { + public Class443(){ + new Class444(); + } +} +class Class444 { + public Class444(){ + new Class445(); + } +} +class Class445 { + public Class445(){ + new Class446(); + } +} +class Class446 { + public Class446(){ + new Class447(); + } +} +class Class447 { + public Class447(){ + new Class448(); + } +} +class Class448 { + public Class448(){ + new Class449(); + } +} +class Class449 { + public Class449(){ + new Class450(); + } +} +class Class450 { + public Class450(){ + new Class451(); + } +} +class Class451 { + public Class451(){ + new Class452(); + } +} +class Class452 { + public Class452(){ + new Class453(); + } +} +class Class453 { + public Class453(){ + new Class454(); + } +} +class Class454 { + public Class454(){ + new Class455(); + } +} +class Class455 { + public Class455(){ + new Class456(); + } +} +class Class456 { + public Class456(){ + new Class457(); + } +} +class Class457 { + public Class457(){ + new Class458(); + } +} +class Class458 { + public Class458(){ + new Class459(); + } +} +class Class459 { + public Class459(){ + new Class460(); + } +} +class Class460 { + public Class460(){ + new Class461(); + } +} +class Class461 { + public Class461(){ + new Class462(); + } +} +class Class462 { + public Class462(){ + new Class463(); + } +} +class Class463 { + public Class463(){ + new Class464(); + } +} +class Class464 { + public Class464(){ + new Class465(); + } +} +class Class465 { + public Class465(){ + new Class466(); + } +} +class Class466 { + public Class466(){ + new Class467(); + } +} +class Class467 { + public Class467(){ + new Class468(); + } +} +class Class468 { + public Class468(){ + new Class469(); + } +} +class Class469 { + public Class469(){ + new Class470(); + } +} +class Class470 { + public Class470(){ + new Class471(); + } +} +class Class471 { + public Class471(){ + new Class472(); + } +} +class Class472 { + public Class472(){ + new Class473(); + } +} +class Class473 { + public Class473(){ + new Class474(); + } +} +class Class474 { + public Class474(){ + new Class475(); + } +} +class Class475 { + public Class475(){ + new Class476(); + } +} +class Class476 { + public Class476(){ + new Class477(); + } +} +class Class477 { + public Class477(){ + new Class478(); + } +} +class Class478 { + public Class478(){ + new Class479(); + } +} +class Class479 { + public Class479(){ + new Class480(); + } +} +class Class480 { + public Class480(){ + new Class481(); + } +} +class Class481 { + public Class481(){ + new Class482(); + } +} +class Class482 { + public Class482(){ + new Class483(); + } +} +class Class483 { + public Class483(){ + new Class484(); + } +} +class Class484 { + public Class484(){ + new Class485(); + } +} +class Class485 { + public Class485(){ + new Class486(); + } +} +class Class486 { + public Class486(){ + new Class487(); + } +} +class Class487 { + public Class487(){ + new Class488(); + } +} +class Class488 { + public Class488(){ + new Class489(); + } +} +class Class489 { + public Class489(){ + new Class490(); + } +} +class Class490 { + public Class490(){ + new Class491(); + } +} +class Class491 { + public Class491(){ + new Class492(); + } +} +class Class492 { + public Class492(){ + new Class493(); + } +} +class Class493 { + public Class493(){ + new Class494(); + } +} +class Class494 { + public Class494(){ + new Class495(); + } +} +class Class495 { + public Class495(){ + new Class496(); + } +} +class Class496 { + public Class496(){ + new Class497(); + } +} +class Class497 { + public Class497(){ + new Class498(); + } +} +class Class498 { + public Class498(){ + new Class499(); + } +} +class Class499 { + public Class499(){ + new Class500(); + } +} +class Class500 { + public Class500(){ + new Class501(); + } +} +class Class501 { + public Class501(){ + new Class502(); + } +} +class Class502 { + public Class502(){ + new Class503(); + } +} +class Class503 { + public Class503(){ + new Class504(); + } +} +class Class504 { + public Class504(){ + new Class505(); + } +} +class Class505 { + public Class505(){ + new Class506(); + } +} +class Class506 { + public Class506(){ + new Class507(); + } +} +class Class507 { + public Class507(){ + new Class508(); + } +} +class Class508 { + public Class508(){ + new Class509(); + } +} +class Class509 { + public Class509(){ + new Class510(); + } +} +class Class510 { + public Class510(){ + new Class511(); + } +} +class Class511 { + public Class511(){ + new Class512(); + } +} +class Class512 { + public Class512(){ + new Class513(); + } +} +class Class513 { + public Class513(){ + new Class514(); + } +} +class Class514 { + public Class514(){ + new Class515(); + } +} +class Class515 { + public Class515(){ + new Class516(); + } +} +class Class516 { + public Class516(){ + new Class517(); + } +} +class Class517 { + public Class517(){ + new Class518(); + } +} +class Class518 { + public Class518(){ + new Class519(); + } +} +class Class519 { + public Class519(){ + new Class520(); + } +} +class Class520 { + public Class520(){ + new Class521(); + } +} +class Class521 { + public Class521(){ + new Class522(); + } +} +class Class522 { + public Class522(){ + new Class523(); + } +} +class Class523 { + public Class523(){ + new Class524(); + } +} +class Class524 { + public Class524(){ + new Class525(); + } +} +class Class525 { + public Class525(){ + new Class526(); + } +} +class Class526 { + public Class526(){ + new Class527(); + } +} +class Class527 { + public Class527(){ + new Class528(); + } +} +class Class528 { + public Class528(){ + new Class529(); + } +} +class Class529 { + public Class529(){ + new Class530(); + } +} +class Class530 { + public Class530(){ + new Class531(); + } +} +class Class531 { + public Class531(){ + new Class532(); + } +} +class Class532 { + public Class532(){ + new Class533(); + } +} +class Class533 { + public Class533(){ + new Class534(); + } +} +class Class534 { + public Class534(){ + new Class535(); + } +} +class Class535 { + public Class535(){ + new Class536(); + } +} +class Class536 { + public Class536(){ + new Class537(); + } +} +class Class537 { + public Class537(){ + new Class538(); + } +} +class Class538 { + public Class538(){ + new Class539(); + } +} +class Class539 { + public Class539(){ + new Class540(); + } +} +class Class540 { + public Class540(){ + new Class541(); + } +} +class Class541 { + public Class541(){ + new Class542(); + } +} +class Class542 { + public Class542(){ + new Class543(); + } +} +class Class543 { + public Class543(){ + new Class544(); + } +} +class Class544 { + public Class544(){ + new Class545(); + } +} +class Class545 { + public Class545(){ + new Class546(); + } +} +class Class546 { + public Class546(){ + new Class547(); + } +} +class Class547 { + public Class547(){ + new Class548(); + } +} +class Class548 { + public Class548(){ + new Class549(); + } +} +class Class549 { + public Class549(){ + new Class550(); + } +} +class Class550 { + public Class550(){ + new Class551(); + } +} +class Class551 { + public Class551(){ + new Class552(); + } +} +class Class552 { + public Class552(){ + new Class553(); + } +} +class Class553 { + public Class553(){ + new Class554(); + } +} +class Class554 { + public Class554(){ + new Class555(); + } +} +class Class555 { + public Class555(){ + new Class556(); + } +} +class Class556 { + public Class556(){ + new Class557(); + } +} +class Class557 { + public Class557(){ + new Class558(); + } +} +class Class558 { + public Class558(){ + new Class559(); + } +} +class Class559 { + public Class559(){ + new Class560(); + } +} +class Class560 { + public Class560(){ + new Class561(); + } +} +class Class561 { + public Class561(){ + new Class562(); + } +} +class Class562 { + public Class562(){ + new Class563(); + } +} +class Class563 { + public Class563(){ + new Class564(); + } +} +class Class564 { + public Class564(){ + new Class565(); + } +} +class Class565 { + public Class565(){ + new Class566(); + } +} +class Class566 { + public Class566(){ + new Class567(); + } +} +class Class567 { + public Class567(){ + new Class568(); + } +} +class Class568 { + public Class568(){ + new Class569(); + } +} +class Class569 { + public Class569(){ + new Class570(); + } +} +class Class570 { + public Class570(){ + new Class571(); + } +} +class Class571 { + public Class571(){ + new Class572(); + } +} +class Class572 { + public Class572(){ + new Class573(); + } +} +class Class573 { + public Class573(){ + new Class574(); + } +} +class Class574 { + public Class574(){ + new Class575(); + } +} +class Class575 { + public Class575(){ + new Class576(); + } +} +class Class576 { + public Class576(){ + new Class577(); + } +} +class Class577 { + public Class577(){ + new Class578(); + } +} +class Class578 { + public Class578(){ + new Class579(); + } +} +class Class579 { + public Class579(){ + new Class580(); + } +} +class Class580 { + public Class580(){ + new Class581(); + } +} +class Class581 { + public Class581(){ + new Class582(); + } +} +class Class582 { + public Class582(){ + new Class583(); + } +} +class Class583 { + public Class583(){ + new Class584(); + } +} +class Class584 { + public Class584(){ + new Class585(); + } +} +class Class585 { + public Class585(){ + new Class586(); + } +} +class Class586 { + public Class586(){ + new Class587(); + } +} +class Class587 { + public Class587(){ + new Class588(); + } +} +class Class588 { + public Class588(){ + new Class589(); + } +} +class Class589 { + public Class589(){ + new Class590(); + } +} +class Class590 { + public Class590(){ + new Class591(); + } +} +class Class591 { + public Class591(){ + new Class592(); + } +} +class Class592 { + public Class592(){ + new Class593(); + } +} +class Class593 { + public Class593(){ + new Class594(); + } +} +class Class594 { + public Class594(){ + new Class595(); + } +} +class Class595 { + public Class595(){ + new Class596(); + } +} +class Class596 { + public Class596(){ + new Class597(); + } +} +class Class597 { + public Class597(){ + new Class598(); + } +} +class Class598 { + public Class598(){ + new Class599(); + } +} +class Class599 { + public Class599(){ + new Class600(); + } +} +class Class600 { + public Class600(){ + new Class601(); + } +} +class Class601 { + public Class601(){ + new Class602(); + } +} +class Class602 { + public Class602(){ + new Class603(); + } +} +class Class603 { + public Class603(){ + new Class604(); + } +} +class Class604 { + public Class604(){ + new Class605(); + } +} +class Class605 { + public Class605(){ + new Class606(); + } +} +class Class606 { + public Class606(){ + new Class607(); + } +} +class Class607 { + public Class607(){ + new Class608(); + } +} +class Class608 { + public Class608(){ + new Class609(); + } +} +class Class609 { + public Class609(){ + new Class610(); + } +} +class Class610 { + public Class610(){ + new Class611(); + } +} +class Class611 { + public Class611(){ + new Class612(); + } +} +class Class612 { + public Class612(){ + new Class613(); + } +} +class Class613 { + public Class613(){ + new Class614(); + } +} +class Class614 { + public Class614(){ + new Class615(); + } +} +class Class615 { + public Class615(){ + new Class616(); + } +} +class Class616 { + public Class616(){ + new Class617(); + } +} +class Class617 { + public Class617(){ + new Class618(); + } +} +class Class618 { + public Class618(){ + new Class619(); + } +} +class Class619 { + public Class619(){ + new Class620(); + } +} +class Class620 { + public Class620(){ + new Class621(); + } +} +class Class621 { + public Class621(){ + new Class622(); + } +} +class Class622 { + public Class622(){ + new Class623(); + } +} +class Class623 { + public Class623(){ + new Class624(); + } +} +class Class624 { + public Class624(){ + new Class625(); + } +} +class Class625 { + public Class625(){ + new Class626(); + } +} +class Class626 { + public Class626(){ + new Class627(); + } +} +class Class627 { + public Class627(){ + new Class628(); + } +} +class Class628 { + public Class628(){ + new Class629(); + } +} +class Class629 { + public Class629(){ + new Class630(); + } +} +class Class630 { + public Class630(){ + new Class631(); + } +} +class Class631 { + public Class631(){ + new Class632(); + } +} +class Class632 { + public Class632(){ + new Class633(); + } +} +class Class633 { + public Class633(){ + new Class634(); + } +} +class Class634 { + public Class634(){ + new Class635(); + } +} +class Class635 { + public Class635(){ + new Class636(); + } +} +class Class636 { + public Class636(){ + new Class637(); + } +} +class Class637 { + public Class637(){ + new Class638(); + } +} +class Class638 { + public Class638(){ + new Class639(); + } +} +class Class639 { + public Class639(){ + new Class640(); + } +} +class Class640 { + public Class640(){ + new Class641(); + } +} +class Class641 { + public Class641(){ + new Class642(); + } +} +class Class642 { + public Class642(){ + new Class643(); + } +} +class Class643 { + public Class643(){ + new Class644(); + } +} +class Class644 { + public Class644(){ + new Class645(); + } +} +class Class645 { + public Class645(){ + new Class646(); + } +} +class Class646 { + public Class646(){ + new Class647(); + } +} +class Class647 { + public Class647(){ + new Class648(); + } +} +class Class648 { + public Class648(){ + new Class649(); + } +} +class Class649 { + public Class649(){ + new Class650(); + } +} +class Class650 { + public Class650(){ + new Class651(); + } +} +class Class651 { + public Class651(){ + new Class652(); + } +} +class Class652 { + public Class652(){ + new Class653(); + } +} +class Class653 { + public Class653(){ + new Class654(); + } +} +class Class654 { + public Class654(){ + new Class655(); + } +} +class Class655 { + public Class655(){ + new Class656(); + } +} +class Class656 { + public Class656(){ + new Class657(); + } +} +class Class657 { + public Class657(){ + new Class658(); + } +} +class Class658 { + public Class658(){ + new Class659(); + } +} +class Class659 { + public Class659(){ + new Class660(); + } +} +class Class660 { + public Class660(){ + new Class661(); + } +} +class Class661 { + public Class661(){ + new Class662(); + } +} +class Class662 { + public Class662(){ + new Class663(); + } +} +class Class663 { + public Class663(){ + new Class664(); + } +} +class Class664 { + public Class664(){ + new Class665(); + } +} +class Class665 { + public Class665(){ + new Class666(); + } +} +class Class666 { + public Class666(){ + new Class667(); + } +} +class Class667 { + public Class667(){ + new Class668(); + } +} +class Class668 { + public Class668(){ + new Class669(); + } +} +class Class669 { + public Class669(){ + new Class670(); + } +} +class Class670 { + public Class670(){ + new Class671(); + } +} +class Class671 { + public Class671(){ + new Class672(); + } +} +class Class672 { + public Class672(){ + new Class673(); + } +} +class Class673 { + public Class673(){ + new Class674(); + } +} +class Class674 { + public Class674(){ + new Class675(); + } +} +class Class675 { + public Class675(){ + new Class676(); + } +} +class Class676 { + public Class676(){ + new Class677(); + } +} +class Class677 { + public Class677(){ + new Class678(); + } +} +class Class678 { + public Class678(){ + new Class679(); + } +} +class Class679 { + public Class679(){ + new Class680(); + } +} +class Class680 { + public Class680(){ + new Class681(); + } +} +class Class681 { + public Class681(){ + new Class682(); + } +} +class Class682 { + public Class682(){ + new Class683(); + } +} +class Class683 { + public Class683(){ + new Class684(); + } +} +class Class684 { + public Class684(){ + new Class685(); + } +} +class Class685 { + public Class685(){ + new Class686(); + } +} +class Class686 { + public Class686(){ + new Class687(); + } +} +class Class687 { + public Class687(){ + new Class688(); + } +} +class Class688 { + public Class688(){ + new Class689(); + } +} +class Class689 { + public Class689(){ + new Class690(); + } +} +class Class690 { + public Class690(){ + new Class691(); + } +} +class Class691 { + public Class691(){ + new Class692(); + } +} +class Class692 { + public Class692(){ + new Class693(); + } +} +class Class693 { + public Class693(){ + new Class694(); + } +} +class Class694 { + public Class694(){ + new Class695(); + } +} +class Class695 { + public Class695(){ + new Class696(); + } +} +class Class696 { + public Class696(){ + new Class697(); + } +} +class Class697 { + public Class697(){ + new Class698(); + } +} +class Class698 { + public Class698(){ + new Class699(); + } +} +class Class699 { + public Class699(){ + new Class700(); + } +} +class Class700 { + public Class700(){ + new Class701(); + } +} +class Class701 { + public Class701(){ + new Class702(); + } +} +class Class702 { + public Class702(){ + new Class703(); + } +} +class Class703 { + public Class703(){ + new Class704(); + } +} +class Class704 { + public Class704(){ + new Class705(); + } +} +class Class705 { + public Class705(){ + new Class706(); + } +} +class Class706 { + public Class706(){ + new Class707(); + } +} +class Class707 { + public Class707(){ + new Class708(); + } +} +class Class708 { + public Class708(){ + new Class709(); + } +} +class Class709 { + public Class709(){ + new Class710(); + } +} +class Class710 { + public Class710(){ + new Class711(); + } +} +class Class711 { + public Class711(){ + new Class712(); + } +} +class Class712 { + public Class712(){ + new Class713(); + } +} +class Class713 { + public Class713(){ + new Class714(); + } +} +class Class714 { + public Class714(){ + new Class715(); + } +} +class Class715 { + public Class715(){ + new Class716(); + } +} +class Class716 { + public Class716(){ + new Class717(); + } +} +class Class717 { + public Class717(){ + new Class718(); + } +} +class Class718 { + public Class718(){ + new Class719(); + } +} +class Class719 { + public Class719(){ + new Class720(); + } +} +class Class720 { + public Class720(){ + new Class721(); + } +} +class Class721 { + public Class721(){ + new Class722(); + } +} +class Class722 { + public Class722(){ + new Class723(); + } +} +class Class723 { + public Class723(){ + new Class724(); + } +} +class Class724 { + public Class724(){ + new Class725(); + } +} +class Class725 { + public Class725(){ + new Class726(); + } +} +class Class726 { + public Class726(){ + new Class727(); + } +} +class Class727 { + public Class727(){ + new Class728(); + } +} +class Class728 { + public Class728(){ + new Class729(); + } +} +class Class729 { + public Class729(){ + new Class730(); + } +} +class Class730 { + public Class730(){ + new Class731(); + } +} +class Class731 { + public Class731(){ + new Class732(); + } +} +class Class732 { + public Class732(){ + new Class733(); + } +} +class Class733 { + public Class733(){ + new Class734(); + } +} +class Class734 { + public Class734(){ + new Class735(); + } +} +class Class735 { + public Class735(){ + new Class736(); + } +} +class Class736 { + public Class736(){ + new Class737(); + } +} +class Class737 { + public Class737(){ + new Class738(); + } +} +class Class738 { + public Class738(){ + new Class739(); + } +} +class Class739 { + public Class739(){ + new Class740(); + } +} +class Class740 { + public Class740(){ + new Class741(); + } +} +class Class741 { + public Class741(){ + new Class742(); + } +} +class Class742 { + public Class742(){ + new Class743(); + } +} +class Class743 { + public Class743(){ + new Class744(); + } +} +class Class744 { + public Class744(){ + new Class745(); + } +} +class Class745 { + public Class745(){ + new Class746(); + } +} +class Class746 { + public Class746(){ + new Class747(); + } +} +class Class747 { + public Class747(){ + new Class748(); + } +} +class Class748 { + public Class748(){ + new Class749(); + } +} +class Class749 { + public Class749(){ + new Class750(); + } +} +class Class750 { + public Class750(){ + new Class751(); + } +} +class Class751 { + public Class751(){ + new Class752(); + } +} +class Class752 { + public Class752(){ + new Class753(); + } +} +class Class753 { + public Class753(){ + new Class754(); + } +} +class Class754 { + public Class754(){ + new Class755(); + } +} +class Class755 { + public Class755(){ + new Class756(); + } +} +class Class756 { + public Class756(){ + new Class757(); + } +} +class Class757 { + public Class757(){ + new Class758(); + } +} +class Class758 { + public Class758(){ + new Class759(); + } +} +class Class759 { + public Class759(){ + new Class760(); + } +} +class Class760 { + public Class760(){ + new Class761(); + } +} +class Class761 { + public Class761(){ + new Class762(); + } +} +class Class762 { + public Class762(){ + new Class763(); + } +} +class Class763 { + public Class763(){ + new Class764(); + } +} +class Class764 { + public Class764(){ + new Class765(); + } +} +class Class765 { + public Class765(){ + new Class766(); + } +} +class Class766 { + public Class766(){ + new Class767(); + } +} +class Class767 { + public Class767(){ + new Class768(); + } +} +class Class768 { + public Class768(){ + new Class769(); + } +} +class Class769 { + public Class769(){ + new Class770(); + } +} +class Class770 { + public Class770(){ + new Class771(); + } +} +class Class771 { + public Class771(){ + new Class772(); + } +} +class Class772 { + public Class772(){ + new Class773(); + } +} +class Class773 { + public Class773(){ + new Class774(); + } +} +class Class774 { + public Class774(){ + new Class775(); + } +} +class Class775 { + public Class775(){ + new Class776(); + } +} +class Class776 { + public Class776(){ + new Class777(); + } +} +class Class777 { + public Class777(){ + new Class778(); + } +} +class Class778 { + public Class778(){ + new Class779(); + } +} +class Class779 { + public Class779(){ + new Class780(); + } +} +class Class780 { + public Class780(){ + new Class781(); + } +} +class Class781 { + public Class781(){ + new Class782(); + } +} +class Class782 { + public Class782(){ + new Class783(); + } +} +class Class783 { + public Class783(){ + new Class784(); + } +} +class Class784 { + public Class784(){ + new Class785(); + } +} +class Class785 { + public Class785(){ + new Class786(); + } +} +class Class786 { + public Class786(){ + new Class787(); + } +} +class Class787 { + public Class787(){ + new Class788(); + } +} +class Class788 { + public Class788(){ + new Class789(); + } +} +class Class789 { + public Class789(){ + new Class790(); + } +} +class Class790 { + public Class790(){ + new Class791(); + } +} +class Class791 { + public Class791(){ + new Class792(); + } +} +class Class792 { + public Class792(){ + new Class793(); + } +} +class Class793 { + public Class793(){ + new Class794(); + } +} +class Class794 { + public Class794(){ + new Class795(); + } +} +class Class795 { + public Class795(){ + new Class796(); + } +} +class Class796 { + public Class796(){ + new Class797(); + } +} +class Class797 { + public Class797(){ + new Class798(); + } +} +class Class798 { + public Class798(){ + new Class799(); + } +} +class Class799 { + public Class799(){ + new Class800(); + } +} +class Class800 { + public Class800(){ + new Class801(); + } +} +class Class801 { + public Class801(){ + new Class802(); + } +} +class Class802 { + public Class802(){ + new Class803(); + } +} +class Class803 { + public Class803(){ + new Class804(); + } +} +class Class804 { + public Class804(){ + new Class805(); + } +} +class Class805 { + public Class805(){ + new Class806(); + } +} +class Class806 { + public Class806(){ + new Class807(); + } +} +class Class807 { + public Class807(){ + new Class808(); + } +} +class Class808 { + public Class808(){ + new Class809(); + } +} +class Class809 { + public Class809(){ + new Class810(); + } +} +class Class810 { + public Class810(){ + new Class811(); + } +} +class Class811 { + public Class811(){ + new Class812(); + } +} +class Class812 { + public Class812(){ + new Class813(); + } +} +class Class813 { + public Class813(){ + new Class814(); + } +} +class Class814 { + public Class814(){ + new Class815(); + } +} +class Class815 { + public Class815(){ + new Class816(); + } +} +class Class816 { + public Class816(){ + new Class817(); + } +} +class Class817 { + public Class817(){ + new Class818(); + } +} +class Class818 { + public Class818(){ + new Class819(); + } +} +class Class819 { + public Class819(){ + new Class820(); + } +} +class Class820 { + public Class820(){ + new Class821(); + } +} +class Class821 { + public Class821(){ + new Class822(); + } +} +class Class822 { + public Class822(){ + new Class823(); + } +} +class Class823 { + public Class823(){ + new Class824(); + } +} +class Class824 { + public Class824(){ + new Class825(); + } +} +class Class825 { + public Class825(){ + new Class826(); + } +} +class Class826 { + public Class826(){ + new Class827(); + } +} +class Class827 { + public Class827(){ + new Class828(); + } +} +class Class828 { + public Class828(){ + new Class829(); + } +} +class Class829 { + public Class829(){ + new Class830(); + } +} +class Class830 { + public Class830(){ + new Class831(); + } +} +class Class831 { + public Class831(){ + new Class832(); + } +} +class Class832 { + public Class832(){ + new Class833(); + } +} +class Class833 { + public Class833(){ + new Class834(); + } +} +class Class834 { + public Class834(){ + new Class835(); + } +} +class Class835 { + public Class835(){ + new Class836(); + } +} +class Class836 { + public Class836(){ + new Class837(); + } +} +class Class837 { + public Class837(){ + new Class838(); + } +} +class Class838 { + public Class838(){ + new Class839(); + } +} +class Class839 { + public Class839(){ + new Class840(); + } +} +class Class840 { + public Class840(){ + new Class841(); + } +} +class Class841 { + public Class841(){ + new Class842(); + } +} +class Class842 { + public Class842(){ + new Class843(); + } +} +class Class843 { + public Class843(){ + new Class844(); + } +} +class Class844 { + public Class844(){ + new Class845(); + } +} +class Class845 { + public Class845(){ + new Class846(); + } +} +class Class846 { + public Class846(){ + new Class847(); + } +} +class Class847 { + public Class847(){ + new Class848(); + } +} +class Class848 { + public Class848(){ + new Class849(); + } +} +class Class849 { + public Class849(){ + new Class850(); + } +} +class Class850 { + public Class850(){ + new Class851(); + } +} +class Class851 { + public Class851(){ + new Class852(); + } +} +class Class852 { + public Class852(){ + new Class853(); + } +} +class Class853 { + public Class853(){ + new Class854(); + } +} +class Class854 { + public Class854(){ + new Class855(); + } +} +class Class855 { + public Class855(){ + new Class856(); + } +} +class Class856 { + public Class856(){ + new Class857(); + } +} +class Class857 { + public Class857(){ + new Class858(); + } +} +class Class858 { + public Class858(){ + new Class859(); + } +} +class Class859 { + public Class859(){ + new Class860(); + } +} +class Class860 { + public Class860(){ + new Class861(); + } +} +class Class861 { + public Class861(){ + new Class862(); + } +} +class Class862 { + public Class862(){ + new Class863(); + } +} +class Class863 { + public Class863(){ + new Class864(); + } +} +class Class864 { + public Class864(){ + new Class865(); + } +} +class Class865 { + public Class865(){ + new Class866(); + } +} +class Class866 { + public Class866(){ + new Class867(); + } +} +class Class867 { + public Class867(){ + new Class868(); + } +} +class Class868 { + public Class868(){ + new Class869(); + } +} +class Class869 { + public Class869(){ + new Class870(); + } +} +class Class870 { + public Class870(){ + new Class871(); + } +} +class Class871 { + public Class871(){ + new Class872(); + } +} +class Class872 { + public Class872(){ + new Class873(); + } +} +class Class873 { + public Class873(){ + new Class874(); + } +} +class Class874 { + public Class874(){ + new Class875(); + } +} +class Class875 { + public Class875(){ + new Class876(); + } +} +class Class876 { + public Class876(){ + new Class877(); + } +} +class Class877 { + public Class877(){ + new Class878(); + } +} +class Class878 { + public Class878(){ + new Class879(); + } +} +class Class879 { + public Class879(){ + new Class880(); + } +} +class Class880 { + public Class880(){ + new Class881(); + } +} +class Class881 { + public Class881(){ + new Class882(); + } +} +class Class882 { + public Class882(){ + new Class883(); + } +} +class Class883 { + public Class883(){ + new Class884(); + } +} +class Class884 { + public Class884(){ + new Class885(); + } +} +class Class885 { + public Class885(){ + new Class886(); + } +} +class Class886 { + public Class886(){ + new Class887(); + } +} +class Class887 { + public Class887(){ + new Class888(); + } +} +class Class888 { + public Class888(){ + new Class889(); + } +} +class Class889 { + public Class889(){ + new Class890(); + } +} +class Class890 { + public Class890(){ + new Class891(); + } +} +class Class891 { + public Class891(){ + new Class892(); + } +} +class Class892 { + public Class892(){ + new Class893(); + } +} +class Class893 { + public Class893(){ + new Class894(); + } +} +class Class894 { + public Class894(){ + new Class895(); + } +} +class Class895 { + public Class895(){ + new Class896(); + } +} +class Class896 { + public Class896(){ + new Class897(); + } +} +class Class897 { + public Class897(){ + new Class898(); + } +} +class Class898 { + public Class898(){ + new Class899(); + } +} +class Class899 { + public Class899(){ + new Class900(); + } +} +class Class900 { + public Class900(){ + new Class901(); + } +} +class Class901 { + public Class901(){ + new Class902(); + } +} +class Class902 { + public Class902(){ + new Class903(); + } +} +class Class903 { + public Class903(){ + new Class904(); + } +} +class Class904 { + public Class904(){ + new Class905(); + } +} +class Class905 { + public Class905(){ + new Class906(); + } +} +class Class906 { + public Class906(){ + new Class907(); + } +} +class Class907 { + public Class907(){ + new Class908(); + } +} +class Class908 { + public Class908(){ + new Class909(); + } +} +class Class909 { + public Class909(){ + new Class910(); + } +} +class Class910 { + public Class910(){ + new Class911(); + } +} +class Class911 { + public Class911(){ + new Class912(); + } +} +class Class912 { + public Class912(){ + new Class913(); + } +} +class Class913 { + public Class913(){ + new Class914(); + } +} +class Class914 { + public Class914(){ + new Class915(); + } +} +class Class915 { + public Class915(){ + new Class916(); + } +} +class Class916 { + public Class916(){ + new Class917(); + } +} +class Class917 { + public Class917(){ + new Class918(); + } +} +class Class918 { + public Class918(){ + new Class919(); + } +} +class Class919 { + public Class919(){ + new Class920(); + } +} +class Class920 { + public Class920(){ + new Class921(); + } +} +class Class921 { + public Class921(){ + new Class922(); + } +} +class Class922 { + public Class922(){ + new Class923(); + } +} +class Class923 { + public Class923(){ + new Class924(); + } +} +class Class924 { + public Class924(){ + new Class925(); + } +} +class Class925 { + public Class925(){ + new Class926(); + } +} +class Class926 { + public Class926(){ + new Class927(); + } +} +class Class927 { + public Class927(){ + new Class928(); + } +} +class Class928 { + public Class928(){ + new Class929(); + } +} +class Class929 { + public Class929(){ + new Class930(); + } +} +class Class930 { + public Class930(){ + new Class931(); + } +} +class Class931 { + public Class931(){ + new Class932(); + } +} +class Class932 { + public Class932(){ + new Class933(); + } +} +class Class933 { + public Class933(){ + new Class934(); + } +} +class Class934 { + public Class934(){ + new Class935(); + } +} +class Class935 { + public Class935(){ + new Class936(); + } +} +class Class936 { + public Class936(){ + new Class937(); + } +} +class Class937 { + public Class937(){ + new Class938(); + } +} +class Class938 { + public Class938(){ + new Class939(); + } +} +class Class939 { + public Class939(){ + new Class940(); + } +} +class Class940 { + public Class940(){ + new Class941(); + } +} +class Class941 { + public Class941(){ + new Class942(); + } +} +class Class942 { + public Class942(){ + new Class943(); + } +} +class Class943 { + public Class943(){ + new Class944(); + } +} +class Class944 { + public Class944(){ + new Class945(); + } +} +class Class945 { + public Class945(){ + new Class946(); + } +} +class Class946 { + public Class946(){ + new Class947(); + } +} +class Class947 { + public Class947(){ + new Class948(); + } +} +class Class948 { + public Class948(){ + new Class949(); + } +} +class Class949 { + public Class949(){ + new Class950(); + } +} +class Class950 { + public Class950(){ + new Class951(); + } +} +class Class951 { + public Class951(){ + new Class952(); + } +} +class Class952 { + public Class952(){ + new Class953(); + } +} +class Class953 { + public Class953(){ + new Class954(); + } +} +class Class954 { + public Class954(){ + new Class955(); + } +} +class Class955 { + public Class955(){ + new Class956(); + } +} +class Class956 { + public Class956(){ + new Class957(); + } +} +class Class957 { + public Class957(){ + new Class958(); + } +} +class Class958 { + public Class958(){ + new Class959(); + } +} +class Class959 { + public Class959(){ + new Class960(); + } +} +class Class960 { + public Class960(){ + new Class961(); + } +} +class Class961 { + public Class961(){ + new Class962(); + } +} +class Class962 { + public Class962(){ + new Class963(); + } +} +class Class963 { + public Class963(){ + new Class964(); + } +} +class Class964 { + public Class964(){ + new Class965(); + } +} +class Class965 { + public Class965(){ + new Class966(); + } +} +class Class966 { + public Class966(){ + new Class967(); + } +} +class Class967 { + public Class967(){ + new Class968(); + } +} +class Class968 { + public Class968(){ + new Class969(); + } +} +class Class969 { + public Class969(){ + new Class970(); + } +} +class Class970 { + public Class970(){ + new Class971(); + } +} +class Class971 { + public Class971(){ + new Class972(); + } +} +class Class972 { + public Class972(){ + new Class973(); + } +} +class Class973 { + public Class973(){ + new Class974(); + } +} +class Class974 { + public Class974(){ + new Class975(); + } +} +class Class975 { + public Class975(){ + new Class976(); + } +} +class Class976 { + public Class976(){ + new Class977(); + } +} +class Class977 { + public Class977(){ + new Class978(); + } +} +class Class978 { + public Class978(){ + new Class979(); + } +} +class Class979 { + public Class979(){ + new Class980(); + } +} +class Class980 { + public Class980(){ + new Class981(); + } +} +class Class981 { + public Class981(){ + new Class982(); + } +} +class Class982 { + public Class982(){ + new Class983(); + } +} +class Class983 { + public Class983(){ + new Class984(); + } +} +class Class984 { + public Class984(){ + new Class985(); + } +} +class Class985 { + public Class985(){ + new Class986(); + } +} +class Class986 { + public Class986(){ + new Class987(); + } +} +class Class987 { + public Class987(){ + new Class988(); + } +} +class Class988 { + public Class988(){ + new Class989(); + } +} +class Class989 { + public Class989(){ + new Class990(); + } +} +class Class990 { + public Class990(){ + new Class991(); + } +} +class Class991 { + public Class991(){ + new Class992(); + } +} +class Class992 { + public Class992(){ + new Class993(); + } +} +class Class993 { + public Class993(){ + new Class994(); + } +} +class Class994 { + public Class994(){ + new Class995(); + } +} +class Class995 { + public Class995(){ + new Class996(); + } +} +class Class996 { + public Class996(){ + new Class997(); + } +} +class Class997 { + public Class997(){ + new Class998(); + } +} +class Class998 { + public Class998(){ + new Class999(); + } +} +class Class999 { + public Class999(){ + new Class1000(); + } +} +class Class1000 { + public Class1000(){ + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinDiag.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinDiag.java new file mode 100644 index 00000000000..58cda02b24f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinDiag.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.runner.RunParams; + +/** + * Helper that prints information about FinMemoryObjects. + */ +public class FinDiag implements Runnable { + private long sleepTime; + + public FinDiag() { + this(RunParams.getInstance().getSleepTime()); + } + + public FinDiag(long sleepTime) { + this.sleepTime = sleepTime; + } + + public void run() { + FinMemoryObject.dumpStatistics(); + // Ensure that interrupt status is not lost + if (Thread.currentThread().isInterrupted()) + return; + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject.java new file mode 100644 index 00000000000..0123d799668 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import java.io.PrintStream; + +/** + * An object that occupies approximately given number of bytes in memory + * and also records number of allocated and finalized instances. + */ +public class FinMemoryObject extends FinMemoryObject1 { + private static int finalizedCount; + + public FinMemoryObject(int size) { + super(size); + } + + protected void finalize() { + synchronized (FinMemoryObject.class) { + ++finalizedCount; + } + } + + /** + * Returns the number of finalized FinMemoryObjects. + */ + public static int getFinalizedCount() { + return finalizedCount; + } + + /** + * Returns the number of live FinMemoryObjects (allocated but not finalized). + */ + public static int getLiveCount() { + return allocatedCount - finalizedCount; + } + + public static void dumpStatistics(PrintStream out) { + Algorithms.tryToPrintln(out, "Object count: " + getLiveCount()); + } + + public static void dumpStatistics() { + dumpStatistics(System.out); + } + + public static boolean isAllFinalized() { + return getLiveCount() == 0; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject1.java new file mode 100644 index 00000000000..80ffffc589b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject1.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import java.io.PrintStream; +import nsk.share.gc.Algorithms; + +/** + * An object that occupies approximately given number of bytes in memory + * and also has finalizer that does nothing. + */ +public class FinMemoryObject1 extends MemoryObject { + protected static int allocatedCount; + + public FinMemoryObject1(int size) { + super(size); + synchronized (FinMemoryObject.class) { + ++allocatedCount; + } + } + + protected void finalize() { + } + + /** + * Returns the number of allocated FinMemoryObjects. + */ + public static int getAllocatedCount() { + return allocatedCount; + } + + public static void dumpStatistics(PrintStream out) { + Algorithms.tryToPrintln(out, "Object count: " + getAllocatedCount()); + } + + public static void dumpStatistics() { + dumpStatistics(System.out); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java new file mode 100644 index 00000000000..6b33783306f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.test.*; +import nsk.share.runner.*; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.gp.GarbageProducerAware; +import nsk.share.gc.gp.GarbageProducer1Aware; +import nsk.share.gc.gp.MemoryStrategy; +import nsk.share.gc.gp.MemoryStrategyAware; +import nsk.share.gc.gp.GarbageUtils; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.LockersAware; +import nsk.share.gc.lock.LockerUtils; + +/** + * Utility methods for GC tests. + */ +public class GC extends nsk.share.test.Tests { + protected static class GCTestRunner extends TestRunner { + private GCParams gcParams; + private GarbageProducer garbageProducer; + private GarbageProducer garbageProducer1; + private MemoryStrategy memoryStrategy; + private Lockers lockers; + + public GCTestRunner(Test test, String[] args) { + super(test, args); + } + + private GCParams getGCParams(String[] args) { + if (gcParams == null) { + gcParams = GCParams.getInstance(); + gcParams.parseCommandLine(args); + } + return gcParams; + } + + private GarbageProducer getGarbageProducer(String[] args) { + if (garbageProducer == null) { + garbageProducer = GarbageUtils.getGarbageProducer(getGCParams(args).getGarbageProducerId()); + configure(garbageProducer); + } + return garbageProducer; + } + + private GarbageProducer getGarbageProducer1(String[] args) { + if (garbageProducer1 == null) { + garbageProducer1 = GarbageUtils.getGarbageProducer(getGCParams(args).getGarbageProducer1Id()); + configure(garbageProducer1); + } + return garbageProducer1; + } + + private MemoryStrategy getMemoryStrategy(String[] args) { + if (memoryStrategy == null) { + memoryStrategy = MemoryStrategy.fromString(getGCParams(args).getMemoryStrategyId()); + configure(memoryStrategy); + } + return memoryStrategy; + } + + private Lockers getLockers(String[] args) { + if (lockers == null) { + lockers = LockerUtils.getLockers(getGCParams(args).getLockersId()); + configure(lockers); + } + return lockers; + } + + public void configure(Object test) { + super.configure(test); + if (test instanceof GCParamsAware) + ((GCParamsAware) test).setGCParams(getGCParams(args)); + if (test instanceof GarbageProducerAware) + ((GarbageProducerAware) test).setGarbageProducer(getGarbageProducer(args)); + if (test instanceof GarbageProducer1Aware) + ((GarbageProducer1Aware) test).setGarbageProducer1(getGarbageProducer1(args)); + if (test instanceof MemoryStrategyAware) + ((MemoryStrategyAware) test).setMemoryStrategy(getMemoryStrategy(args)); + if (test instanceof LockersAware) + ((LockersAware) test).setLockers(getLockers(args)); + } + + + } + + private GC() { + } + + public static void runTest(Test test, String[] args) { + new GCTestRunner(test, args).run(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParams.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParams.java new file mode 100644 index 00000000000..02b65dceb8d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParams.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import java.io.PrintStream; + +public class GCParams { + private String garbageProducerId; + private String garbageProducer1Id; + private String memoryStrategyId; + private String lockersId; + + public final String getGarbageProducerId() { + return garbageProducerId; + } + + public final void setGarbageProducerId(String garbageProducerId) { + this.garbageProducerId = garbageProducerId; + } + + public final String getGarbageProducer1Id() { + return garbageProducer1Id; + } + + public final void setGarbageProducer1Id(String garbageProducer1Id) { + this.garbageProducer1Id = garbageProducer1Id; + } + + public final String getMemoryStrategyId() { + return memoryStrategyId; + } + + public final void setMemoryStrategyId(String memoryStrategyId) { + this.memoryStrategyId = memoryStrategyId; + } + + public final String getLockersId() { + return lockersId; + } + + public final void setLockersId(String lockersId) { + this.lockersId = lockersId; + } + + public void parseCommandLine(String[] args) { + if (args == null) + return; + for (int i = 0; i < args.length; ++i) { + if (args[i].equals("-gp")) + garbageProducerId = args[++i]; + else if (args[i].equals("-gp1")) + garbageProducer1Id = args[++i]; + else if (args[i].equals("-ms")) + memoryStrategyId = args[++i]; + else if (args[i].equals("-lockers")) + lockersId = args[++i]; + } + printConfig(System.out); + } + + public void prinUsage() { + } + + public void printConfig(PrintStream out) { + } + + private static GCParams instance; + + public static GCParams getInstance() { + synchronized (GCParams.class) { + if (instance == null) + instance = new GCParams(); + return instance; + } + } + + public static void setInstance(GCParams gcParams) { + synchronized (GCParams.class) { + instance = gcParams; + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParamsAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParamsAware.java new file mode 100644 index 00000000000..190dd9cbf5d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParamsAware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +/** + * Marker interface to signify that run params are needed. + */ +public interface GCParamsAware { + public void setGCParams(GCParams gcParams); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCTestBase.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCTestBase.java new file mode 100644 index 00000000000..7421da7b769 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCTestBase.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.test.TestBase; +import nsk.share.runner.RunParams; +import nsk.share.runner.RunParamsAware; + +public abstract class GCTestBase extends TestBase implements RunParamsAware, GCParamsAware { + protected RunParams runParams; + protected GCParams gcParams; + + public final void setRunParams(RunParams runParams) { + this.runParams = runParams; + } + + public final void setGCParams(GCParams gcParams) { + this.gcParams = gcParams; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/IndexPair.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/IndexPair.java new file mode 100644 index 00000000000..ed48ea3ac38 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/IndexPair.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +public final class IndexPair { + private int i, j; + + public IndexPair(int i, int j) { + setI(i); + setJ(j); + } + + public int getI() { + return i; + } + + public void setI(int i) { + this.i = i; + } + + public int getJ() { + return j; + } + + public void setJ(int j) { + this.j = j; + } + + public boolean equals(IndexPair pair) { + return (this.i == pair.i && this.j == pair.j); + } + + public boolean equals(Object o) { + return o instanceof IndexPair && equals((IndexPair) o); + } + + public int hashCode() { + return i << 16 + j; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/LinkedMemoryObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/LinkedMemoryObject.java new file mode 100644 index 00000000000..15257903220 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/LinkedMemoryObject.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +/** + * An object that occupies approximately given number of bytes in memory + * and has forward and backward links to other objects. + */ +public class LinkedMemoryObject extends MemoryObject { + private LinkedMemoryObject next; + private LinkedMemoryObject prev; + + /** + * Create an object that occupies given number of bytes. + * + * @param arraySize size + */ + public LinkedMemoryObject(int size) { + super(size - 2 * Memory.getReferenceSize()); + } + + public LinkedMemoryObject(int size, LinkedMemoryObject next) { + super(size - 2 * Memory.getReferenceSize()); + setNext(next); + } + + public LinkedMemoryObject(int size, LinkedMemoryObject next, LinkedMemoryObject prev) { + super(size - 2 * Memory.getReferenceSize()); + setNext(next); + setPrev(prev); + } + + public final void setNext(LinkedMemoryObject next) { + this.next = next; + } + + public final void setPrev(LinkedMemoryObject prev) { + this.prev = prev; + } + + public final LinkedMemoryObject getNext() { + return next; + } + + public final LinkedMemoryObject getPrev() { + return prev; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Matrix.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Matrix.java new file mode 100644 index 00000000000..73587b7a06f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Matrix.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +public class Matrix { + private int cellSize; + private int matrixSize; + private Cell matrix[][]; + private int nKnockedOut; // number of cells "nulled out" + + public Matrix(int matrixSize, int cellSize) { + this.matrixSize = matrixSize; + this.cellSize = cellSize; + matrix = new Cell[matrixSize][matrixSize]; + populate(); + } + + public void populate() { + for (int i = 0; i < matrixSize ; i++) { + for( int j = 0 ; j < matrixSize ; j++) { + matrix[i][j] = new Cell(cellSize, i); + } + } + } + + public int returnArrayBound() { + return matrixSize - 1; + } + + public synchronized void clear(int i, int j) { + matrix[i][j] = null; + ++nKnockedOut; + } + + public synchronized void repopulate(int i, int j) { + matrix[i][j] = new Cell(cellSize, i + j); + --nKnockedOut; + } + + public synchronized void resetCellCount() { + nKnockedOut = 0; + } + + public synchronized int getCellCount() { + return nKnockedOut; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java new file mode 100644 index 00000000000..f5c70671e5e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.test.LocalRandom; +import java.io.PrintStream; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.tree.*; +import nsk.share.gc.gp.MemoryStrategy; +import nsk.share.log.Log; + +/** + * Different utility methods to work with memory objects. + */ +public final class Memory { + private static int bits = 0; + private static int referenceSize = 0; + private static int objectExtraSize = 0; + + private Memory() { + } + + private static int getBits() { + if (bits == 0) + bits = Integer.parseInt(System.getProperty("sun.arch.data.model")); + return bits; + } + + /** + * Get size of one object reference. + * + * TODO: somehow determine the real value + */ + public static int getReferenceSize() { + if (referenceSize == 0) + referenceSize = (getBits() == 64) ? 8 : 4; + return referenceSize; + } + + /** + * Get size of primitive type int. + */ + public static int getIntSize() { + return 4; + } + + /** + * Get size of primitive type boolean. + */ + public static int getBooleanSize() { + return 1; + } + + /** + * Get size of primitive type byte. + */ + public static int getByteSize() { + return 1; + } + + /** + * Get size of primitive type char. + */ + public static int getCharSize() { + return 2; + } + + /** + * Get size of primitive type short. + */ + public static int getShortSize() { + return 2; + } + + /** + * Get size of primitive type long. + */ + public static int getLongSize() { + return 8; + } + + /** + * Get size of primitive type float. + */ + public static int getFloatSize() { + return 4; + } + + /** + * Get size of primitive type double. + */ + public static int getDoubleSize() { + return 8; + } + + /** + * Get how many extra bytes an object occupies in the heap + * compared to sum of it's fields. + * + * TODO: somehow determine the real value + */ + public static int getObjectExtraSize() { + if (objectExtraSize == 0) + objectExtraSize = 2 * getReferenceSize(); + return objectExtraSize; + } + /** + * Get how many extra bytes an array occupies in the heap + * compared to sum of it's fields. + * + * TODO: somehow determine the real value + */ + public static int getArrayExtraSize() { + return getObjectExtraSize(); + } + + /** + * Return size of reference object (SoftReference, WeakReference, PhantomReference) + */ + public static int getReferenceObjectSize() { + return getReferenceSize() + getObjectExtraSize(); + } + + /** + * Get an approximate length of array that will occupy a given memory. + * + * @param memory size of memory + * @param objectSize size of each object in array + * @return length of array + */ + public static int getArrayLength(long memory, long objectSize) { + int referenceSize = getReferenceSize(); + int arrayExtraSize = getArrayExtraSize(); + return (int) Math.min( + (memory - arrayExtraSize) / (objectSize + referenceSize), + Integer.MAX_VALUE + ); + } + + /** + * Get an approximate size of array of given length and object size. + * + * @param length length of arary + * @param objectSize size of object in array + * @return size of array + */ + public static long getArraySize(int length, long objectSize) { + return getObjectExtraSize() + length * (objectSize + getReferenceSize()); + } + + /** + * Calculate approximate size of biggest of MemoryObjects. + */ + public static long getMemoryObjectSize(long size) { + return size + 2 * getReferenceSize() + getObjectExtraSize(); + } + + /** + * Calculate approximate size of linked list in memory. + * + * @param length length of list + * @param size size of object + * @return size + */ + public static long getListSize(int length, int size) { + return getObjectExtraSize() + length * (getReferenceSize() + getMemoryObjectSize(size)); + } + + /** + * Calculate length of linear or circular linked list. + * + * @param mobj head of list + * @return length of list + */ + public static int getListLength(LinkedMemoryObject mobj) { + LinkedMemoryObject tobj = mobj; + int length = 0; + do { + ++length; + tobj = tobj.getNext(); + } while (tobj != null && tobj != mobj); + return length; + } + + /** + * Calculate length of array of linear or circular linked lists. + * + * @param mobjs array containting heads of lists + * @return length of all lists + */ + public static int getListsLength(LinkedMemoryObject[] mobjs) { + int length = 0; + for (int i = 0; i < mobjs.length; ++i) { + LinkedMemoryObject mobj = mobjs[i]; + if (mobj != null) + length += getListLength(mobj); + } + return length; + } + + /** + * Calculate size of all objects in linear or circular linked list. + * + * @param mobj head of list + * @return size of list + */ + public static long getListSize(LinkedMemoryObject mobj) { + LinkedMemoryObject tobj = mobj; + long size = 0; + do { + size += tobj.getSize(); + tobj = tobj.getNext(); + } while (tobj != null && tobj != mobj); + return size; + } + + /** + * Calculate size of array of linear or circular linked lists. + * + * @param mobjs array containting heads of lists + * @return size of all lists + */ + public static long getListsSize(LinkedMemoryObject[] mobjs) { + long size = 0; + for (int i = 0; i < mobjs.length; ++i) { + LinkedMemoryObject mobj = mobjs[i]; + if (mobj != null) + size += getListSize(mobj); + } + return size; + } + + /** + * Create singly linked linear list of objects of fixed size. + * + * @param depth length of list + * @param size size of each object + * @return head of created list or null if depth = 0 + */ + public static LinkedMemoryObject makeLinearList(int depth, int size) { + LinkedMemoryObject mobj = null; + for (int i = 0; i < depth; ++i) + mobj = new LinkedMemoryObject(size, mobj); + return mobj; + } + + /** + * Create singly linked linear list of objects of varying size. + * + * @param depth length of list + * @param size maximum size of each object + * @return head of created list or null if depth = 0 + */ + public static LinkedMemoryObject makeRandomLinearList(int depth, int size) { + if (depth == 0) + return null; + LinkedMemoryObject mobj = new LinkedMemoryObject(size); + for (int i = 0; i < depth - 1; ++i) + mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj); + return mobj; + } + + /** + * Create singly linked circular linear list of objects of fixed size. + * + * @param depth length of list + * @param size size of each object + * @return head of created list or null if depth = 0 + */ + public static LinkedMemoryObject makeCircularList(int depth, int size) { + if (depth == 0) + return null; + LinkedMemoryObject mobj = new LinkedMemoryObject(size); + LinkedMemoryObject tmpobj = mobj; + for (int i = 1; i < depth; i++) + mobj = new LinkedMemoryObject(size, mobj); + tmpobj.setNext(mobj); + return tmpobj; + } + + /** + * Create singly linked circular linear list of objects of varying size. + * + * @param depth length of list + * @param size maximum size of each object + * @return head of created list or null if depth = 0 + */ + public static LinkedMemoryObject makeRandomCircularList(int depth, int size) { + if (depth == 0) + return null; + LinkedMemoryObject mobj = new LinkedMemoryObject(size); + LinkedMemoryObject tmpobj = mobj; + for (int i = 0; i < depth - 1; i++) + mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj); + tmpobj.setNext(mobj); + return tmpobj; + } + + /** + * Create new nonbranchy binary tree. + * + * Each node in the tree except leaves always has left son. A node + * will have right son with probability branchiness. + * + * @param numberOfNodes number of nodes + * @param branchiness branchiness + * @param size size of each node + * @return root of created tree + */ + public static LinkedMemoryObject makeNonbranchyTree(int numberOfNodes, float branchiness, int size) { + LinkedMemoryObject root = null; + LinkedMemoryObject current = null; + if (numberOfNodes == 0) + return null; + else if (numberOfNodes == 1) + return new LinkedMemoryObject(size); + else if (numberOfNodes == 2) + return new LinkedMemoryObject(size, makeNonbranchyTree(1, branchiness, size)); + else { + if (LocalRandom.nextFloat() < branchiness) { + int numberOfLeftNodes = LocalRandom.nextInt(1, numberOfNodes - 1); + int numberOfRightNodes = numberOfNodes - 1 - numberOfLeftNodes; + return new LinkedMemoryObject( + size, + makeNonbranchyTree(numberOfLeftNodes, branchiness, size), + makeNonbranchyTree(numberOfRightNodes, branchiness, size) + ); + } else { + return new LinkedMemoryObject(size, makeNonbranchyTree(numberOfNodes - 1, branchiness, size)); + } + } + } + + /** + * Create a balanced tree of given height. + * + * @param height height of the tree + * @param size size of each node + * @return created tree + */ + public static Tree makeBalancedTree(int height, long size) { + return new Tree(makeBalancedTreeNode(height, size)); + } + + /** + * Get a number of nodes in balanced tree of given height. + * + * @param heigh height of the tree + * @return number of nodes + */ + public static int balancedTreeNodes(int height) { + if (height == 0) + return 0; + int n = 1; + while (height > 1) { + n *= 2; + height--; + } + return n * 2 - 1; + } + + /** + * Get approximate memory size occupied by balanced tree + * of given height and given node size. + * + * @param height height of the tree + * @param nodeSize size of each node + * @return memory size + */ + public static long balancedTreeSize(int height, long nodeSize) { + return balancedTreeNodes(height) * nodeSize; + } + + /** + * Get a height of balanced tree with given number of nodes. + * + * @param nodes number of nodes + * @return height of the tree + */ + public static int balancedTreeHeightFromNodes(int nodes) { + if (nodes == 0) + return 0; + int h = 1; + long n = 1; + while (n + n - 1 <= nodes) { + n = n + n; + h = h + 1; + } + return h - 1; + } + + /** + * Get approximate height of balanced tree which will occupy + * given memory with given node size. + * + * @param memory memory size + * @param nodeSize size of each node + * @return approximate height of the tree + */ + public static int balancedTreeHeightFromMemory(long memory, long nodeSize) { + return balancedTreeHeightFromNodes((int) (memory / nodeSize)); + } + + /** + * Create balanced tree of given height and node size. + * + * @param height height of the tree + * @param size size of each node + * @return root of created tree + */ + public static TreeNode makeBalancedTreeNode(int height, long size) { + if (height == 0) + return null; + else + return new TreeNode(size, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size)); + } + + /** + * Create balanced tree of given height and node size. + * + * @param height height of the tree + * @param size size of each node + * @return root of created tree + */ + public static TreeNode makeBalancedTreeNode(int height, long size, GarbageProducer gp) { + if (height == 0) + return null; + else + return new TreeNode(size, gp, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size)); + } + + /** + * Determine if given tree is a balanced tree. + * + * @param tree tree + * @return true if tree is balanced + */ + public static boolean isBalancedTree(TreeNode tree) { + return + tree.getActualHeight() == tree.getHeight() && + tree.getShortestPath() == tree.getHeight(); + } + + /** + * Fill an array of MemoryObject's with new objects of given size. + * + * @param array array + * @param count number of objects to create + * @param size size of each object + */ + public static void fillArray(MemoryObject[] array, int count, int size) { + for (int i = 0; i < count; ++i) + array[i] = new MemoryObject(size); + } + + /** + * Fill an array of MemoryObject's with new objects of random size. + * + * @param array array + * @param count number of objects to create + * @param size maximum size of each object + */ + public static void fillArrayRandom(MemoryObject[] array, int count, int size) { + for (int i = 0; i < count; ++i) + array[i] = new MemoryObject(LocalRandom.nextInt(size)); + } + + /** + * Fill an array of MemoryObject's with new objects of random size. + * + * @param array array + * @param count number of objects to create + * @param size maximum size of each object + */ + public static void fillArrayRandom(LinkedMemoryObject[] array, int count, int size) { + for (int i = 0; i < count; ++i) + array[i] = new LinkedMemoryObject(LocalRandom.nextInt(size)); + } + + public static void dumpStatistics(PrintStream out) { + out.println(Runtime.getRuntime().freeMemory()); + out.flush(); + } + + public static void dumpStatistics(Log log) { + log.info(Runtime.getRuntime().freeMemory()); + } + + public static void dumpStatistics() { + dumpStatistics(System.out); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/MemoryObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/MemoryObject.java new file mode 100644 index 00000000000..66dd77aebea --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/MemoryObject.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +/** + * An object that occupies approximately given number of bytes in memory. + */ +public class MemoryObject { + private static int diff = (int) Memory.getObjectExtraSize(); + private byte storage[]; + + /** + * Create an object that occupies given number of bytes. + * + * @param size size + */ + public MemoryObject(int size) { + if (size > diff) + storage = new byte[size - diff]; + } + + public final byte[] getStorage() { + return storage; + } + + public final int getSize() { + return storage.length; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java new file mode 100644 index 00000000000..4f51b140e1c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import java.io.*; +import java.util.*; + +import nsk.share.test.ExecutionController; + +/** + * NonbranchyTree defines a tree structure. Each node of the tree + * always has one son. A node may have the second son with probability + * branchiness. + */ +public class NonbranchyTree { + + /** Minimal size of each node (in bytes) */ + public final static int MIN_NODE_SIZE = 20; + private Node root; + private Random random; + private int numberOfNodes; + private float branchiness; + private int size; + private ExecutionController controller; + + /** + * Creates a new tree with number of nodes not more than + * numberOfNodes. The implementation uses recursion to build the + * tree, so if StackOverflowError or OutOfMemoryError is + * thrown, the recursion is stopped and the method finishes building of the + * tree. Each node consists of byte[] of length size. + * + * @param numberOfNodes maximum number of nodes for the tree. + * @param branchiness probability for each node to have the second son. + * @param size number of bytes to store in a node. + * + * @throws IllegalArgumentException if numberOfNodes is + * less than 1; or branchiness is greater than 1, or less + * or equal than 0; or size is less than 1. + * + */ + public NonbranchyTree(int numberOfNodes, float branchiness, int size) { + this(numberOfNodes, branchiness, size, new Random(System.currentTimeMillis()), null); + initTree(); + } + + public NonbranchyTree(int numberOfNodes, float branchiness, int size, ExecutionController controller) { + this(numberOfNodes, branchiness, size, new Random(System.currentTimeMillis()), controller); + initTree(); + } + + private NonbranchyTree(int numberOfNodes, float branchiness, int size, Random random, ExecutionController controller) { + this.numberOfNodes = numberOfNodes; + this.branchiness = branchiness; + this.size = size; + this.random = random; + this.controller = controller; + } + + private void initTree() { + if (numberOfNodes < 1) { + throw new IllegalArgumentException("Illegal number of nodes: " + + numberOfNodes + ", must be at " + + "least 1."); + } + if ( (branchiness >= 1) || (branchiness <= 0) ) { + throw new IllegalArgumentException("Illegal value of branchiness: " + + numberOfNodes + ", must be at " + + "greater than 0 and less than " + + " 1."); + } + if (size < 1) { + throw new IllegalArgumentException("Illegal size of nodes: " + + size + ", must be at least 1."); + } + root = createTree(numberOfNodes, size); + } + + // Create a new tree with specified number of nodes and size of each node + private Node createTree(int numberOfNodes, int size) { + // Make sure we respect the controller and stop test after + // given time. + if (controller != null && !controller.continueExecution()) { + return null; + } + + Node node = new Node(size); + try { + if (numberOfNodes == 0) { + // No more nodes need to be built + return null; + } else if (numberOfNodes == 1) { + return node; + } else if (numberOfNodes == 2) { + node.left = createTree(1, size); + return node; + } else { + // Create a few nodes + if (makeRightNode()) { + // The node will have two sons + int leftNodes = 1 + random.nextInt(numberOfNodes - 2); + int rightNodes = numberOfNodes - 1 - leftNodes; + + node.left = createTree(leftNodes, size); + node.right = createTree(rightNodes, size); + } else { + // The node will have just one son + Node leftTree = createTree(numberOfNodes - 1, size); + node.left = leftTree; + } + return node; + } // if + } catch(StackOverflowError e) { + // No more memory for such long tree + return node; + } catch(OutOfMemoryError e) { + // No more memory for such long tree + return node; + } // try + } // createTree() + + // Define the "branchiness" of the tree + private boolean makeRightNode() { + return (random.nextFloat() < branchiness); + } + + /** + * Bends the tree. A son of a leaf of the tree is set to the root node. + * + */ + public void bend() { + bend(root); + } + + // Bend the tree: make a reference from a leat of the tree to the specified + // node + private void bend(Node markedNode) { + Node node = root; + + while ( (node.left != null) || (node.right != null) ) + node = node.left; + node.right = markedNode; + } + + /** + * Prints the whole tree from the root to the defined PrintStream. + * + * @param out PrintStream to print the tree in + * + */ + public void print(PrintStream out) { + print(out, root); + } + + // Print the sub-tree from the specified node and down + private void print(PrintStream out, Node node) { + node.print(out); + if (node.left != null) + print(out, node.left); + if (node.right != null) + print(out, node.right); + } +} + +// The class defines a node of a tree +class Node { + Node left; + Node right; + byte[] core; + + Node(int size) { + left = null; + right = null; + core = new byte[size]; + + // Initizlize the core array + for (int i = 0; i < size; i++) + core[i] = (byte) i; + } + + // Print the node info + void print(PrintStream out) { + out.println("node = " + this + " (" + left + ", " + right + ")"); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/OOMStress.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/OOMStress.java new file mode 100644 index 00000000000..76a7f99a3ce --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/OOMStress.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +/** + * Marker interface to tell that a something stresses OOM. + */ +public interface OOMStress { +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ThreadedGCTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ThreadedGCTest.java new file mode 100644 index 00000000000..cd99bd31b8b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ThreadedGCTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc; + +import nsk.share.runner.*; +import nsk.share.test.ExecutionController; +import nsk.share.Consts; + +/** + * Test that executes a number of tasks. + * + * How these tasks are used is determined by MultiRunner. + * Usually they are executed in separate threads in cycle + * for some time or for some iterations. + * + * @see nsk.share.runner.MultiRunner + * @see nsk.share.runner.ThreadsRunner + */ +public abstract class ThreadedGCTest extends GCTestBase implements MultiRunnerAware { + private MultiRunner runner; + + /** + * Create a task with index i. + * + * Subclasses should to override this method + * to created neccessary tasks. + * + * @param i index of task + * @return task to run or null + */ + protected abstract Runnable createRunnable(int i); + + protected ExecutionController getExecutionController() { + return runner.getExecutionController(); + } + + protected final boolean runThreads() { + for (int i = 0; i < runParams.getNumberOfThreads(); ++i) { + Runnable runnable = createRunnable(i); + if (runnable != null) + runner.add(runnable); + } + runner.run(); + return runner.isSuccessful(); + } + + public void run() { + if (!runThreads()) + setFailed(true); + } + + public final void setRunner(MultiRunner runner) { + this.runner = runner; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/TwoFieldsObject.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/TwoFieldsObject.java new file mode 100644 index 00000000000..369925fb7e4 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/TwoFieldsObject.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.gc; + +/** + * An object with two fields of same type. + */ +public class TwoFieldsObject { + private T left, right; + + public TwoFieldsObject(T left, T right) { + setLeft(left); + setRight(right); + } + + public final void setLeft(T left) { + this.left = left; + } + + public final void setRight(T right) { + this.right = right; + } + + public final T getLeft() { + return left; + } + + public final T getRight() { + return right; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/classes/Classes.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/classes/Classes.java new file mode 100644 index 00000000000..8883a06306f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/classes/Classes.java @@ -0,0 +1,5024 @@ +/* + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.classes; + +class Class1 { + public Class1(){ + + } +} +class Class2 { + public Class2(){ + + } +} +class Class3 { + public Class3(){ + + } +} +class Class4 { + public Class4(){ + + } +} +class Class5 { + public Class5(){ + + } +} +class Class6 { + public Class6(){ + + } +} +class Class7 { + public Class7(){ + + } +} +class Class8 { + public Class8(){ + + } +} +class Class9 { + public Class9(){ + + } +} +class Class10 { + public Class10(){ + + } +} +class Class11 { + public Class11(){ + + } +} +class Class12 { + public Class12(){ + + } +} +class Class13 { + public Class13(){ + + } +} +class Class14 { + public Class14(){ + + } +} +class Class15 { + public Class15(){ + + } +} +class Class16 { + public Class16(){ + + } +} +class Class17 { + public Class17(){ + + } +} +class Class18 { + public Class18(){ + + } +} +class Class19 { + public Class19(){ + + } +} +class Class20 { + public Class20(){ + + } +} +class Class21 { + public Class21(){ + + } +} +class Class22 { + public Class22(){ + + } +} +class Class23 { + public Class23(){ + + } +} +class Class24 { + public Class24(){ + + } +} +class Class25 { + public Class25(){ + + } +} +class Class26 { + public Class26(){ + + } +} +class Class27 { + public Class27(){ + + } +} +class Class28 { + public Class28(){ + + } +} +class Class29 { + public Class29(){ + + } +} +class Class30 { + public Class30(){ + + } +} +class Class31 { + public Class31(){ + + } +} +class Class32 { + public Class32(){ + + } +} +class Class33 { + public Class33(){ + + } +} +class Class34 { + public Class34(){ + + } +} +class Class35 { + public Class35(){ + + } +} +class Class36 { + public Class36(){ + + } +} +class Class37 { + public Class37(){ + + } +} +class Class38 { + public Class38(){ + + } +} +class Class39 { + public Class39(){ + + } +} +class Class40 { + public Class40(){ + + } +} +class Class41 { + public Class41(){ + + } +} +class Class42 { + public Class42(){ + + } +} +class Class43 { + public Class43(){ + + } +} +class Class44 { + public Class44(){ + + } +} +class Class45 { + public Class45(){ + + } +} +class Class46 { + public Class46(){ + + } +} +class Class47 { + public Class47(){ + + } +} +class Class48 { + public Class48(){ + + } +} +class Class49 { + public Class49(){ + + } +} +class Class50 { + public Class50(){ + + } +} +class Class51 { + public Class51(){ + + } +} +class Class52 { + public Class52(){ + + } +} +class Class53 { + public Class53(){ + + } +} +class Class54 { + public Class54(){ + + } +} +class Class55 { + public Class55(){ + + } +} +class Class56 { + public Class56(){ + + } +} +class Class57 { + public Class57(){ + + } +} +class Class58 { + public Class58(){ + + } +} +class Class59 { + public Class59(){ + + } +} +class Class60 { + public Class60(){ + + } +} +class Class61 { + public Class61(){ + + } +} +class Class62 { + public Class62(){ + + } +} +class Class63 { + public Class63(){ + + } +} +class Class64 { + public Class64(){ + + } +} +class Class65 { + public Class65(){ + + } +} +class Class66 { + public Class66(){ + + } +} +class Class67 { + public Class67(){ + + } +} +class Class68 { + public Class68(){ + + } +} +class Class69 { + public Class69(){ + + } +} +class Class70 { + public Class70(){ + + } +} +class Class71 { + public Class71(){ + + } +} +class Class72 { + public Class72(){ + + } +} +class Class73 { + public Class73(){ + + } +} +class Class74 { + public Class74(){ + + } +} +class Class75 { + public Class75(){ + + } +} +class Class76 { + public Class76(){ + + } +} +class Class77 { + public Class77(){ + + } +} +class Class78 { + public Class78(){ + + } +} +class Class79 { + public Class79(){ + + } +} +class Class80 { + public Class80(){ + + } +} +class Class81 { + public Class81(){ + + } +} +class Class82 { + public Class82(){ + + } +} +class Class83 { + public Class83(){ + + } +} +class Class84 { + public Class84(){ + + } +} +class Class85 { + public Class85(){ + + } +} +class Class86 { + public Class86(){ + + } +} +class Class87 { + public Class87(){ + + } +} +class Class88 { + public Class88(){ + + } +} +class Class89 { + public Class89(){ + + } +} +class Class90 { + public Class90(){ + + } +} +class Class91 { + public Class91(){ + + } +} +class Class92 { + public Class92(){ + + } +} +class Class93 { + public Class93(){ + + } +} +class Class94 { + public Class94(){ + + } +} +class Class95 { + public Class95(){ + + } +} +class Class96 { + public Class96(){ + + } +} +class Class97 { + public Class97(){ + + } +} +class Class98 { + public Class98(){ + + } +} +class Class99 { + public Class99(){ + + } +} +class Class100 { + public Class100(){ + + } +} +class Class101 { + public Class101(){ + + } +} +class Class102 { + public Class102(){ + + } +} +class Class103 { + public Class103(){ + + } +} +class Class104 { + public Class104(){ + + } +} +class Class105 { + public Class105(){ + + } +} +class Class106 { + public Class106(){ + + } +} +class Class107 { + public Class107(){ + + } +} +class Class108 { + public Class108(){ + + } +} +class Class109 { + public Class109(){ + + } +} +class Class110 { + public Class110(){ + + } +} +class Class111 { + public Class111(){ + + } +} +class Class112 { + public Class112(){ + + } +} +class Class113 { + public Class113(){ + + } +} +class Class114 { + public Class114(){ + + } +} +class Class115 { + public Class115(){ + + } +} +class Class116 { + public Class116(){ + + } +} +class Class117 { + public Class117(){ + + } +} +class Class118 { + public Class118(){ + + } +} +class Class119 { + public Class119(){ + + } +} +class Class120 { + public Class120(){ + + } +} +class Class121 { + public Class121(){ + + } +} +class Class122 { + public Class122(){ + + } +} +class Class123 { + public Class123(){ + + } +} +class Class124 { + public Class124(){ + + } +} +class Class125 { + public Class125(){ + + } +} +class Class126 { + public Class126(){ + + } +} +class Class127 { + public Class127(){ + + } +} +class Class128 { + public Class128(){ + + } +} +class Class129 { + public Class129(){ + + } +} +class Class130 { + public Class130(){ + + } +} +class Class131 { + public Class131(){ + + } +} +class Class132 { + public Class132(){ + + } +} +class Class133 { + public Class133(){ + + } +} +class Class134 { + public Class134(){ + + } +} +class Class135 { + public Class135(){ + + } +} +class Class136 { + public Class136(){ + + } +} +class Class137 { + public Class137(){ + + } +} +class Class138 { + public Class138(){ + + } +} +class Class139 { + public Class139(){ + + } +} +class Class140 { + public Class140(){ + + } +} +class Class141 { + public Class141(){ + + } +} +class Class142 { + public Class142(){ + + } +} +class Class143 { + public Class143(){ + + } +} +class Class144 { + public Class144(){ + + } +} +class Class145 { + public Class145(){ + + } +} +class Class146 { + public Class146(){ + + } +} +class Class147 { + public Class147(){ + + } +} +class Class148 { + public Class148(){ + + } +} +class Class149 { + public Class149(){ + + } +} +class Class150 { + public Class150(){ + + } +} +class Class151 { + public Class151(){ + + } +} +class Class152 { + public Class152(){ + + } +} +class Class153 { + public Class153(){ + + } +} +class Class154 { + public Class154(){ + + } +} +class Class155 { + public Class155(){ + + } +} +class Class156 { + public Class156(){ + + } +} +class Class157 { + public Class157(){ + + } +} +class Class158 { + public Class158(){ + + } +} +class Class159 { + public Class159(){ + + } +} +class Class160 { + public Class160(){ + + } +} +class Class161 { + public Class161(){ + + } +} +class Class162 { + public Class162(){ + + } +} +class Class163 { + public Class163(){ + + } +} +class Class164 { + public Class164(){ + + } +} +class Class165 { + public Class165(){ + + } +} +class Class166 { + public Class166(){ + + } +} +class Class167 { + public Class167(){ + + } +} +class Class168 { + public Class168(){ + + } +} +class Class169 { + public Class169(){ + + } +} +class Class170 { + public Class170(){ + + } +} +class Class171 { + public Class171(){ + + } +} +class Class172 { + public Class172(){ + + } +} +class Class173 { + public Class173(){ + + } +} +class Class174 { + public Class174(){ + + } +} +class Class175 { + public Class175(){ + + } +} +class Class176 { + public Class176(){ + + } +} +class Class177 { + public Class177(){ + + } +} +class Class178 { + public Class178(){ + + } +} +class Class179 { + public Class179(){ + + } +} +class Class180 { + public Class180(){ + + } +} +class Class181 { + public Class181(){ + + } +} +class Class182 { + public Class182(){ + + } +} +class Class183 { + public Class183(){ + + } +} +class Class184 { + public Class184(){ + + } +} +class Class185 { + public Class185(){ + + } +} +class Class186 { + public Class186(){ + + } +} +class Class187 { + public Class187(){ + + } +} +class Class188 { + public Class188(){ + + } +} +class Class189 { + public Class189(){ + + } +} +class Class190 { + public Class190(){ + + } +} +class Class191 { + public Class191(){ + + } +} +class Class192 { + public Class192(){ + + } +} +class Class193 { + public Class193(){ + + } +} +class Class194 { + public Class194(){ + + } +} +class Class195 { + public Class195(){ + + } +} +class Class196 { + public Class196(){ + + } +} +class Class197 { + public Class197(){ + + } +} +class Class198 { + public Class198(){ + + } +} +class Class199 { + public Class199(){ + + } +} +class Class200 { + public Class200(){ + + } +} +class Class201 { + public Class201(){ + + } +} +class Class202 { + public Class202(){ + + } +} +class Class203 { + public Class203(){ + + } +} +class Class204 { + public Class204(){ + + } +} +class Class205 { + public Class205(){ + + } +} +class Class206 { + public Class206(){ + + } +} +class Class207 { + public Class207(){ + + } +} +class Class208 { + public Class208(){ + + } +} +class Class209 { + public Class209(){ + + } +} +class Class210 { + public Class210(){ + + } +} +class Class211 { + public Class211(){ + + } +} +class Class212 { + public Class212(){ + + } +} +class Class213 { + public Class213(){ + + } +} +class Class214 { + public Class214(){ + + } +} +class Class215 { + public Class215(){ + + } +} +class Class216 { + public Class216(){ + + } +} +class Class217 { + public Class217(){ + + } +} +class Class218 { + public Class218(){ + + } +} +class Class219 { + public Class219(){ + + } +} +class Class220 { + public Class220(){ + + } +} +class Class221 { + public Class221(){ + + } +} +class Class222 { + public Class222(){ + + } +} +class Class223 { + public Class223(){ + + } +} +class Class224 { + public Class224(){ + + } +} +class Class225 { + public Class225(){ + + } +} +class Class226 { + public Class226(){ + + } +} +class Class227 { + public Class227(){ + + } +} +class Class228 { + public Class228(){ + + } +} +class Class229 { + public Class229(){ + + } +} +class Class230 { + public Class230(){ + + } +} +class Class231 { + public Class231(){ + + } +} +class Class232 { + public Class232(){ + + } +} +class Class233 { + public Class233(){ + + } +} +class Class234 { + public Class234(){ + + } +} +class Class235 { + public Class235(){ + + } +} +class Class236 { + public Class236(){ + + } +} +class Class237 { + public Class237(){ + + } +} +class Class238 { + public Class238(){ + + } +} +class Class239 { + public Class239(){ + + } +} +class Class240 { + public Class240(){ + + } +} +class Class241 { + public Class241(){ + + } +} +class Class242 { + public Class242(){ + + } +} +class Class243 { + public Class243(){ + + } +} +class Class244 { + public Class244(){ + + } +} +class Class245 { + public Class245(){ + + } +} +class Class246 { + public Class246(){ + + } +} +class Class247 { + public Class247(){ + + } +} +class Class248 { + public Class248(){ + + } +} +class Class249 { + public Class249(){ + + } +} +class Class250 { + public Class250(){ + + } +} +class Class251 { + public Class251(){ + + } +} +class Class252 { + public Class252(){ + + } +} +class Class253 { + public Class253(){ + + } +} +class Class254 { + public Class254(){ + + } +} +class Class255 { + public Class255(){ + + } +} +class Class256 { + public Class256(){ + + } +} +class Class257 { + public Class257(){ + + } +} +class Class258 { + public Class258(){ + + } +} +class Class259 { + public Class259(){ + + } +} +class Class260 { + public Class260(){ + + } +} +class Class261 { + public Class261(){ + + } +} +class Class262 { + public Class262(){ + + } +} +class Class263 { + public Class263(){ + + } +} +class Class264 { + public Class264(){ + + } +} +class Class265 { + public Class265(){ + + } +} +class Class266 { + public Class266(){ + + } +} +class Class267 { + public Class267(){ + + } +} +class Class268 { + public Class268(){ + + } +} +class Class269 { + public Class269(){ + + } +} +class Class270 { + public Class270(){ + + } +} +class Class271 { + public Class271(){ + + } +} +class Class272 { + public Class272(){ + + } +} +class Class273 { + public Class273(){ + + } +} +class Class274 { + public Class274(){ + + } +} +class Class275 { + public Class275(){ + + } +} +class Class276 { + public Class276(){ + + } +} +class Class277 { + public Class277(){ + + } +} +class Class278 { + public Class278(){ + + } +} +class Class279 { + public Class279(){ + + } +} +class Class280 { + public Class280(){ + + } +} +class Class281 { + public Class281(){ + + } +} +class Class282 { + public Class282(){ + + } +} +class Class283 { + public Class283(){ + + } +} +class Class284 { + public Class284(){ + + } +} +class Class285 { + public Class285(){ + + } +} +class Class286 { + public Class286(){ + + } +} +class Class287 { + public Class287(){ + + } +} +class Class288 { + public Class288(){ + + } +} +class Class289 { + public Class289(){ + + } +} +class Class290 { + public Class290(){ + + } +} +class Class291 { + public Class291(){ + + } +} +class Class292 { + public Class292(){ + + } +} +class Class293 { + public Class293(){ + + } +} +class Class294 { + public Class294(){ + + } +} +class Class295 { + public Class295(){ + + } +} +class Class296 { + public Class296(){ + + } +} +class Class297 { + public Class297(){ + + } +} +class Class298 { + public Class298(){ + + } +} +class Class299 { + public Class299(){ + + } +} +class Class300 { + public Class300(){ + + } +} +class Class301 { + public Class301(){ + + } +} +class Class302 { + public Class302(){ + + } +} +class Class303 { + public Class303(){ + + } +} +class Class304 { + public Class304(){ + + } +} +class Class305 { + public Class305(){ + + } +} +class Class306 { + public Class306(){ + + } +} +class Class307 { + public Class307(){ + + } +} +class Class308 { + public Class308(){ + + } +} +class Class309 { + public Class309(){ + + } +} +class Class310 { + public Class310(){ + + } +} +class Class311 { + public Class311(){ + + } +} +class Class312 { + public Class312(){ + + } +} +class Class313 { + public Class313(){ + + } +} +class Class314 { + public Class314(){ + + } +} +class Class315 { + public Class315(){ + + } +} +class Class316 { + public Class316(){ + + } +} +class Class317 { + public Class317(){ + + } +} +class Class318 { + public Class318(){ + + } +} +class Class319 { + public Class319(){ + + } +} +class Class320 { + public Class320(){ + + } +} +class Class321 { + public Class321(){ + + } +} +class Class322 { + public Class322(){ + + } +} +class Class323 { + public Class323(){ + + } +} +class Class324 { + public Class324(){ + + } +} +class Class325 { + public Class325(){ + + } +} +class Class326 { + public Class326(){ + + } +} +class Class327 { + public Class327(){ + + } +} +class Class328 { + public Class328(){ + + } +} +class Class329 { + public Class329(){ + + } +} +class Class330 { + public Class330(){ + + } +} +class Class331 { + public Class331(){ + + } +} +class Class332 { + public Class332(){ + + } +} +class Class333 { + public Class333(){ + + } +} +class Class334 { + public Class334(){ + + } +} +class Class335 { + public Class335(){ + + } +} +class Class336 { + public Class336(){ + + } +} +class Class337 { + public Class337(){ + + } +} +class Class338 { + public Class338(){ + + } +} +class Class339 { + public Class339(){ + + } +} +class Class340 { + public Class340(){ + + } +} +class Class341 { + public Class341(){ + + } +} +class Class342 { + public Class342(){ + + } +} +class Class343 { + public Class343(){ + + } +} +class Class344 { + public Class344(){ + + } +} +class Class345 { + public Class345(){ + + } +} +class Class346 { + public Class346(){ + + } +} +class Class347 { + public Class347(){ + + } +} +class Class348 { + public Class348(){ + + } +} +class Class349 { + public Class349(){ + + } +} +class Class350 { + public Class350(){ + + } +} +class Class351 { + public Class351(){ + + } +} +class Class352 { + public Class352(){ + + } +} +class Class353 { + public Class353(){ + + } +} +class Class354 { + public Class354(){ + + } +} +class Class355 { + public Class355(){ + + } +} +class Class356 { + public Class356(){ + + } +} +class Class357 { + public Class357(){ + + } +} +class Class358 { + public Class358(){ + + } +} +class Class359 { + public Class359(){ + + } +} +class Class360 { + public Class360(){ + + } +} +class Class361 { + public Class361(){ + + } +} +class Class362 { + public Class362(){ + + } +} +class Class363 { + public Class363(){ + + } +} +class Class364 { + public Class364(){ + + } +} +class Class365 { + public Class365(){ + + } +} +class Class366 { + public Class366(){ + + } +} +class Class367 { + public Class367(){ + + } +} +class Class368 { + public Class368(){ + + } +} +class Class369 { + public Class369(){ + + } +} +class Class370 { + public Class370(){ + + } +} +class Class371 { + public Class371(){ + + } +} +class Class372 { + public Class372(){ + + } +} +class Class373 { + public Class373(){ + + } +} +class Class374 { + public Class374(){ + + } +} +class Class375 { + public Class375(){ + + } +} +class Class376 { + public Class376(){ + + } +} +class Class377 { + public Class377(){ + + } +} +class Class378 { + public Class378(){ + + } +} +class Class379 { + public Class379(){ + + } +} +class Class380 { + public Class380(){ + + } +} +class Class381 { + public Class381(){ + + } +} +class Class382 { + public Class382(){ + + } +} +class Class383 { + public Class383(){ + + } +} +class Class384 { + public Class384(){ + + } +} +class Class385 { + public Class385(){ + + } +} +class Class386 { + public Class386(){ + + } +} +class Class387 { + public Class387(){ + + } +} +class Class388 { + public Class388(){ + + } +} +class Class389 { + public Class389(){ + + } +} +class Class390 { + public Class390(){ + + } +} +class Class391 { + public Class391(){ + + } +} +class Class392 { + public Class392(){ + + } +} +class Class393 { + public Class393(){ + + } +} +class Class394 { + public Class394(){ + + } +} +class Class395 { + public Class395(){ + + } +} +class Class396 { + public Class396(){ + + } +} +class Class397 { + public Class397(){ + + } +} +class Class398 { + public Class398(){ + + } +} +class Class399 { + public Class399(){ + + } +} +class Class400 { + public Class400(){ + + } +} +class Class401 { + public Class401(){ + + } +} +class Class402 { + public Class402(){ + + } +} +class Class403 { + public Class403(){ + + } +} +class Class404 { + public Class404(){ + + } +} +class Class405 { + public Class405(){ + + } +} +class Class406 { + public Class406(){ + + } +} +class Class407 { + public Class407(){ + + } +} +class Class408 { + public Class408(){ + + } +} +class Class409 { + public Class409(){ + + } +} +class Class410 { + public Class410(){ + + } +} +class Class411 { + public Class411(){ + + } +} +class Class412 { + public Class412(){ + + } +} +class Class413 { + public Class413(){ + + } +} +class Class414 { + public Class414(){ + + } +} +class Class415 { + public Class415(){ + + } +} +class Class416 { + public Class416(){ + + } +} +class Class417 { + public Class417(){ + + } +} +class Class418 { + public Class418(){ + + } +} +class Class419 { + public Class419(){ + + } +} +class Class420 { + public Class420(){ + + } +} +class Class421 { + public Class421(){ + + } +} +class Class422 { + public Class422(){ + + } +} +class Class423 { + public Class423(){ + + } +} +class Class424 { + public Class424(){ + + } +} +class Class425 { + public Class425(){ + + } +} +class Class426 { + public Class426(){ + + } +} +class Class427 { + public Class427(){ + + } +} +class Class428 { + public Class428(){ + + } +} +class Class429 { + public Class429(){ + + } +} +class Class430 { + public Class430(){ + + } +} +class Class431 { + public Class431(){ + + } +} +class Class432 { + public Class432(){ + + } +} +class Class433 { + public Class433(){ + + } +} +class Class434 { + public Class434(){ + + } +} +class Class435 { + public Class435(){ + + } +} +class Class436 { + public Class436(){ + + } +} +class Class437 { + public Class437(){ + + } +} +class Class438 { + public Class438(){ + + } +} +class Class439 { + public Class439(){ + + } +} +class Class440 { + public Class440(){ + + } +} +class Class441 { + public Class441(){ + + } +} +class Class442 { + public Class442(){ + + } +} +class Class443 { + public Class443(){ + + } +} +class Class444 { + public Class444(){ + + } +} +class Class445 { + public Class445(){ + + } +} +class Class446 { + public Class446(){ + + } +} +class Class447 { + public Class447(){ + + } +} +class Class448 { + public Class448(){ + + } +} +class Class449 { + public Class449(){ + + } +} +class Class450 { + public Class450(){ + + } +} +class Class451 { + public Class451(){ + + } +} +class Class452 { + public Class452(){ + + } +} +class Class453 { + public Class453(){ + + } +} +class Class454 { + public Class454(){ + + } +} +class Class455 { + public Class455(){ + + } +} +class Class456 { + public Class456(){ + + } +} +class Class457 { + public Class457(){ + + } +} +class Class458 { + public Class458(){ + + } +} +class Class459 { + public Class459(){ + + } +} +class Class460 { + public Class460(){ + + } +} +class Class461 { + public Class461(){ + + } +} +class Class462 { + public Class462(){ + + } +} +class Class463 { + public Class463(){ + + } +} +class Class464 { + public Class464(){ + + } +} +class Class465 { + public Class465(){ + + } +} +class Class466 { + public Class466(){ + + } +} +class Class467 { + public Class467(){ + + } +} +class Class468 { + public Class468(){ + + } +} +class Class469 { + public Class469(){ + + } +} +class Class470 { + public Class470(){ + + } +} +class Class471 { + public Class471(){ + + } +} +class Class472 { + public Class472(){ + + } +} +class Class473 { + public Class473(){ + + } +} +class Class474 { + public Class474(){ + + } +} +class Class475 { + public Class475(){ + + } +} +class Class476 { + public Class476(){ + + } +} +class Class477 { + public Class477(){ + + } +} +class Class478 { + public Class478(){ + + } +} +class Class479 { + public Class479(){ + + } +} +class Class480 { + public Class480(){ + + } +} +class Class481 { + public Class481(){ + + } +} +class Class482 { + public Class482(){ + + } +} +class Class483 { + public Class483(){ + + } +} +class Class484 { + public Class484(){ + + } +} +class Class485 { + public Class485(){ + + } +} +class Class486 { + public Class486(){ + + } +} +class Class487 { + public Class487(){ + + } +} +class Class488 { + public Class488(){ + + } +} +class Class489 { + public Class489(){ + + } +} +class Class490 { + public Class490(){ + + } +} +class Class491 { + public Class491(){ + + } +} +class Class492 { + public Class492(){ + + } +} +class Class493 { + public Class493(){ + + } +} +class Class494 { + public Class494(){ + + } +} +class Class495 { + public Class495(){ + + } +} +class Class496 { + public Class496(){ + + } +} +class Class497 { + public Class497(){ + + } +} +class Class498 { + public Class498(){ + + } +} +class Class499 { + public Class499(){ + + } +} +class Class500 { + public Class500(){ + + } +} +class Class501 { + public Class501(){ + + } +} +class Class502 { + public Class502(){ + + } +} +class Class503 { + public Class503(){ + + } +} +class Class504 { + public Class504(){ + + } +} +class Class505 { + public Class505(){ + + } +} +class Class506 { + public Class506(){ + + } +} +class Class507 { + public Class507(){ + + } +} +class Class508 { + public Class508(){ + + } +} +class Class509 { + public Class509(){ + + } +} +class Class510 { + public Class510(){ + + } +} +class Class511 { + public Class511(){ + + } +} +class Class512 { + public Class512(){ + + } +} +class Class513 { + public Class513(){ + + } +} +class Class514 { + public Class514(){ + + } +} +class Class515 { + public Class515(){ + + } +} +class Class516 { + public Class516(){ + + } +} +class Class517 { + public Class517(){ + + } +} +class Class518 { + public Class518(){ + + } +} +class Class519 { + public Class519(){ + + } +} +class Class520 { + public Class520(){ + + } +} +class Class521 { + public Class521(){ + + } +} +class Class522 { + public Class522(){ + + } +} +class Class523 { + public Class523(){ + + } +} +class Class524 { + public Class524(){ + + } +} +class Class525 { + public Class525(){ + + } +} +class Class526 { + public Class526(){ + + } +} +class Class527 { + public Class527(){ + + } +} +class Class528 { + public Class528(){ + + } +} +class Class529 { + public Class529(){ + + } +} +class Class530 { + public Class530(){ + + } +} +class Class531 { + public Class531(){ + + } +} +class Class532 { + public Class532(){ + + } +} +class Class533 { + public Class533(){ + + } +} +class Class534 { + public Class534(){ + + } +} +class Class535 { + public Class535(){ + + } +} +class Class536 { + public Class536(){ + + } +} +class Class537 { + public Class537(){ + + } +} +class Class538 { + public Class538(){ + + } +} +class Class539 { + public Class539(){ + + } +} +class Class540 { + public Class540(){ + + } +} +class Class541 { + public Class541(){ + + } +} +class Class542 { + public Class542(){ + + } +} +class Class543 { + public Class543(){ + + } +} +class Class544 { + public Class544(){ + + } +} +class Class545 { + public Class545(){ + + } +} +class Class546 { + public Class546(){ + + } +} +class Class547 { + public Class547(){ + + } +} +class Class548 { + public Class548(){ + + } +} +class Class549 { + public Class549(){ + + } +} +class Class550 { + public Class550(){ + + } +} +class Class551 { + public Class551(){ + + } +} +class Class552 { + public Class552(){ + + } +} +class Class553 { + public Class553(){ + + } +} +class Class554 { + public Class554(){ + + } +} +class Class555 { + public Class555(){ + + } +} +class Class556 { + public Class556(){ + + } +} +class Class557 { + public Class557(){ + + } +} +class Class558 { + public Class558(){ + + } +} +class Class559 { + public Class559(){ + + } +} +class Class560 { + public Class560(){ + + } +} +class Class561 { + public Class561(){ + + } +} +class Class562 { + public Class562(){ + + } +} +class Class563 { + public Class563(){ + + } +} +class Class564 { + public Class564(){ + + } +} +class Class565 { + public Class565(){ + + } +} +class Class566 { + public Class566(){ + + } +} +class Class567 { + public Class567(){ + + } +} +class Class568 { + public Class568(){ + + } +} +class Class569 { + public Class569(){ + + } +} +class Class570 { + public Class570(){ + + } +} +class Class571 { + public Class571(){ + + } +} +class Class572 { + public Class572(){ + + } +} +class Class573 { + public Class573(){ + + } +} +class Class574 { + public Class574(){ + + } +} +class Class575 { + public Class575(){ + + } +} +class Class576 { + public Class576(){ + + } +} +class Class577 { + public Class577(){ + + } +} +class Class578 { + public Class578(){ + + } +} +class Class579 { + public Class579(){ + + } +} +class Class580 { + public Class580(){ + + } +} +class Class581 { + public Class581(){ + + } +} +class Class582 { + public Class582(){ + + } +} +class Class583 { + public Class583(){ + + } +} +class Class584 { + public Class584(){ + + } +} +class Class585 { + public Class585(){ + + } +} +class Class586 { + public Class586(){ + + } +} +class Class587 { + public Class587(){ + + } +} +class Class588 { + public Class588(){ + + } +} +class Class589 { + public Class589(){ + + } +} +class Class590 { + public Class590(){ + + } +} +class Class591 { + public Class591(){ + + } +} +class Class592 { + public Class592(){ + + } +} +class Class593 { + public Class593(){ + + } +} +class Class594 { + public Class594(){ + + } +} +class Class595 { + public Class595(){ + + } +} +class Class596 { + public Class596(){ + + } +} +class Class597 { + public Class597(){ + + } +} +class Class598 { + public Class598(){ + + } +} +class Class599 { + public Class599(){ + + } +} +class Class600 { + public Class600(){ + + } +} +class Class601 { + public Class601(){ + + } +} +class Class602 { + public Class602(){ + + } +} +class Class603 { + public Class603(){ + + } +} +class Class604 { + public Class604(){ + + } +} +class Class605 { + public Class605(){ + + } +} +class Class606 { + public Class606(){ + + } +} +class Class607 { + public Class607(){ + + } +} +class Class608 { + public Class608(){ + + } +} +class Class609 { + public Class609(){ + + } +} +class Class610 { + public Class610(){ + + } +} +class Class611 { + public Class611(){ + + } +} +class Class612 { + public Class612(){ + + } +} +class Class613 { + public Class613(){ + + } +} +class Class614 { + public Class614(){ + + } +} +class Class615 { + public Class615(){ + + } +} +class Class616 { + public Class616(){ + + } +} +class Class617 { + public Class617(){ + + } +} +class Class618 { + public Class618(){ + + } +} +class Class619 { + public Class619(){ + + } +} +class Class620 { + public Class620(){ + + } +} +class Class621 { + public Class621(){ + + } +} +class Class622 { + public Class622(){ + + } +} +class Class623 { + public Class623(){ + + } +} +class Class624 { + public Class624(){ + + } +} +class Class625 { + public Class625(){ + + } +} +class Class626 { + public Class626(){ + + } +} +class Class627 { + public Class627(){ + + } +} +class Class628 { + public Class628(){ + + } +} +class Class629 { + public Class629(){ + + } +} +class Class630 { + public Class630(){ + + } +} +class Class631 { + public Class631(){ + + } +} +class Class632 { + public Class632(){ + + } +} +class Class633 { + public Class633(){ + + } +} +class Class634 { + public Class634(){ + + } +} +class Class635 { + public Class635(){ + + } +} +class Class636 { + public Class636(){ + + } +} +class Class637 { + public Class637(){ + + } +} +class Class638 { + public Class638(){ + + } +} +class Class639 { + public Class639(){ + + } +} +class Class640 { + public Class640(){ + + } +} +class Class641 { + public Class641(){ + + } +} +class Class642 { + public Class642(){ + + } +} +class Class643 { + public Class643(){ + + } +} +class Class644 { + public Class644(){ + + } +} +class Class645 { + public Class645(){ + + } +} +class Class646 { + public Class646(){ + + } +} +class Class647 { + public Class647(){ + + } +} +class Class648 { + public Class648(){ + + } +} +class Class649 { + public Class649(){ + + } +} +class Class650 { + public Class650(){ + + } +} +class Class651 { + public Class651(){ + + } +} +class Class652 { + public Class652(){ + + } +} +class Class653 { + public Class653(){ + + } +} +class Class654 { + public Class654(){ + + } +} +class Class655 { + public Class655(){ + + } +} +class Class656 { + public Class656(){ + + } +} +class Class657 { + public Class657(){ + + } +} +class Class658 { + public Class658(){ + + } +} +class Class659 { + public Class659(){ + + } +} +class Class660 { + public Class660(){ + + } +} +class Class661 { + public Class661(){ + + } +} +class Class662 { + public Class662(){ + + } +} +class Class663 { + public Class663(){ + + } +} +class Class664 { + public Class664(){ + + } +} +class Class665 { + public Class665(){ + + } +} +class Class666 { + public Class666(){ + + } +} +class Class667 { + public Class667(){ + + } +} +class Class668 { + public Class668(){ + + } +} +class Class669 { + public Class669(){ + + } +} +class Class670 { + public Class670(){ + + } +} +class Class671 { + public Class671(){ + + } +} +class Class672 { + public Class672(){ + + } +} +class Class673 { + public Class673(){ + + } +} +class Class674 { + public Class674(){ + + } +} +class Class675 { + public Class675(){ + + } +} +class Class676 { + public Class676(){ + + } +} +class Class677 { + public Class677(){ + + } +} +class Class678 { + public Class678(){ + + } +} +class Class679 { + public Class679(){ + + } +} +class Class680 { + public Class680(){ + + } +} +class Class681 { + public Class681(){ + + } +} +class Class682 { + public Class682(){ + + } +} +class Class683 { + public Class683(){ + + } +} +class Class684 { + public Class684(){ + + } +} +class Class685 { + public Class685(){ + + } +} +class Class686 { + public Class686(){ + + } +} +class Class687 { + public Class687(){ + + } +} +class Class688 { + public Class688(){ + + } +} +class Class689 { + public Class689(){ + + } +} +class Class690 { + public Class690(){ + + } +} +class Class691 { + public Class691(){ + + } +} +class Class692 { + public Class692(){ + + } +} +class Class693 { + public Class693(){ + + } +} +class Class694 { + public Class694(){ + + } +} +class Class695 { + public Class695(){ + + } +} +class Class696 { + public Class696(){ + + } +} +class Class697 { + public Class697(){ + + } +} +class Class698 { + public Class698(){ + + } +} +class Class699 { + public Class699(){ + + } +} +class Class700 { + public Class700(){ + + } +} +class Class701 { + public Class701(){ + + } +} +class Class702 { + public Class702(){ + + } +} +class Class703 { + public Class703(){ + + } +} +class Class704 { + public Class704(){ + + } +} +class Class705 { + public Class705(){ + + } +} +class Class706 { + public Class706(){ + + } +} +class Class707 { + public Class707(){ + + } +} +class Class708 { + public Class708(){ + + } +} +class Class709 { + public Class709(){ + + } +} +class Class710 { + public Class710(){ + + } +} +class Class711 { + public Class711(){ + + } +} +class Class712 { + public Class712(){ + + } +} +class Class713 { + public Class713(){ + + } +} +class Class714 { + public Class714(){ + + } +} +class Class715 { + public Class715(){ + + } +} +class Class716 { + public Class716(){ + + } +} +class Class717 { + public Class717(){ + + } +} +class Class718 { + public Class718(){ + + } +} +class Class719 { + public Class719(){ + + } +} +class Class720 { + public Class720(){ + + } +} +class Class721 { + public Class721(){ + + } +} +class Class722 { + public Class722(){ + + } +} +class Class723 { + public Class723(){ + + } +} +class Class724 { + public Class724(){ + + } +} +class Class725 { + public Class725(){ + + } +} +class Class726 { + public Class726(){ + + } +} +class Class727 { + public Class727(){ + + } +} +class Class728 { + public Class728(){ + + } +} +class Class729 { + public Class729(){ + + } +} +class Class730 { + public Class730(){ + + } +} +class Class731 { + public Class731(){ + + } +} +class Class732 { + public Class732(){ + + } +} +class Class733 { + public Class733(){ + + } +} +class Class734 { + public Class734(){ + + } +} +class Class735 { + public Class735(){ + + } +} +class Class736 { + public Class736(){ + + } +} +class Class737 { + public Class737(){ + + } +} +class Class738 { + public Class738(){ + + } +} +class Class739 { + public Class739(){ + + } +} +class Class740 { + public Class740(){ + + } +} +class Class741 { + public Class741(){ + + } +} +class Class742 { + public Class742(){ + + } +} +class Class743 { + public Class743(){ + + } +} +class Class744 { + public Class744(){ + + } +} +class Class745 { + public Class745(){ + + } +} +class Class746 { + public Class746(){ + + } +} +class Class747 { + public Class747(){ + + } +} +class Class748 { + public Class748(){ + + } +} +class Class749 { + public Class749(){ + + } +} +class Class750 { + public Class750(){ + + } +} +class Class751 { + public Class751(){ + + } +} +class Class752 { + public Class752(){ + + } +} +class Class753 { + public Class753(){ + + } +} +class Class754 { + public Class754(){ + + } +} +class Class755 { + public Class755(){ + + } +} +class Class756 { + public Class756(){ + + } +} +class Class757 { + public Class757(){ + + } +} +class Class758 { + public Class758(){ + + } +} +class Class759 { + public Class759(){ + + } +} +class Class760 { + public Class760(){ + + } +} +class Class761 { + public Class761(){ + + } +} +class Class762 { + public Class762(){ + + } +} +class Class763 { + public Class763(){ + + } +} +class Class764 { + public Class764(){ + + } +} +class Class765 { + public Class765(){ + + } +} +class Class766 { + public Class766(){ + + } +} +class Class767 { + public Class767(){ + + } +} +class Class768 { + public Class768(){ + + } +} +class Class769 { + public Class769(){ + + } +} +class Class770 { + public Class770(){ + + } +} +class Class771 { + public Class771(){ + + } +} +class Class772 { + public Class772(){ + + } +} +class Class773 { + public Class773(){ + + } +} +class Class774 { + public Class774(){ + + } +} +class Class775 { + public Class775(){ + + } +} +class Class776 { + public Class776(){ + + } +} +class Class777 { + public Class777(){ + + } +} +class Class778 { + public Class778(){ + + } +} +class Class779 { + public Class779(){ + + } +} +class Class780 { + public Class780(){ + + } +} +class Class781 { + public Class781(){ + + } +} +class Class782 { + public Class782(){ + + } +} +class Class783 { + public Class783(){ + + } +} +class Class784 { + public Class784(){ + + } +} +class Class785 { + public Class785(){ + + } +} +class Class786 { + public Class786(){ + + } +} +class Class787 { + public Class787(){ + + } +} +class Class788 { + public Class788(){ + + } +} +class Class789 { + public Class789(){ + + } +} +class Class790 { + public Class790(){ + + } +} +class Class791 { + public Class791(){ + + } +} +class Class792 { + public Class792(){ + + } +} +class Class793 { + public Class793(){ + + } +} +class Class794 { + public Class794(){ + + } +} +class Class795 { + public Class795(){ + + } +} +class Class796 { + public Class796(){ + + } +} +class Class797 { + public Class797(){ + + } +} +class Class798 { + public Class798(){ + + } +} +class Class799 { + public Class799(){ + + } +} +class Class800 { + public Class800(){ + + } +} +class Class801 { + public Class801(){ + + } +} +class Class802 { + public Class802(){ + + } +} +class Class803 { + public Class803(){ + + } +} +class Class804 { + public Class804(){ + + } +} +class Class805 { + public Class805(){ + + } +} +class Class806 { + public Class806(){ + + } +} +class Class807 { + public Class807(){ + + } +} +class Class808 { + public Class808(){ + + } +} +class Class809 { + public Class809(){ + + } +} +class Class810 { + public Class810(){ + + } +} +class Class811 { + public Class811(){ + + } +} +class Class812 { + public Class812(){ + + } +} +class Class813 { + public Class813(){ + + } +} +class Class814 { + public Class814(){ + + } +} +class Class815 { + public Class815(){ + + } +} +class Class816 { + public Class816(){ + + } +} +class Class817 { + public Class817(){ + + } +} +class Class818 { + public Class818(){ + + } +} +class Class819 { + public Class819(){ + + } +} +class Class820 { + public Class820(){ + + } +} +class Class821 { + public Class821(){ + + } +} +class Class822 { + public Class822(){ + + } +} +class Class823 { + public Class823(){ + + } +} +class Class824 { + public Class824(){ + + } +} +class Class825 { + public Class825(){ + + } +} +class Class826 { + public Class826(){ + + } +} +class Class827 { + public Class827(){ + + } +} +class Class828 { + public Class828(){ + + } +} +class Class829 { + public Class829(){ + + } +} +class Class830 { + public Class830(){ + + } +} +class Class831 { + public Class831(){ + + } +} +class Class832 { + public Class832(){ + + } +} +class Class833 { + public Class833(){ + + } +} +class Class834 { + public Class834(){ + + } +} +class Class835 { + public Class835(){ + + } +} +class Class836 { + public Class836(){ + + } +} +class Class837 { + public Class837(){ + + } +} +class Class838 { + public Class838(){ + + } +} +class Class839 { + public Class839(){ + + } +} +class Class840 { + public Class840(){ + + } +} +class Class841 { + public Class841(){ + + } +} +class Class842 { + public Class842(){ + + } +} +class Class843 { + public Class843(){ + + } +} +class Class844 { + public Class844(){ + + } +} +class Class845 { + public Class845(){ + + } +} +class Class846 { + public Class846(){ + + } +} +class Class847 { + public Class847(){ + + } +} +class Class848 { + public Class848(){ + + } +} +class Class849 { + public Class849(){ + + } +} +class Class850 { + public Class850(){ + + } +} +class Class851 { + public Class851(){ + + } +} +class Class852 { + public Class852(){ + + } +} +class Class853 { + public Class853(){ + + } +} +class Class854 { + public Class854(){ + + } +} +class Class855 { + public Class855(){ + + } +} +class Class856 { + public Class856(){ + + } +} +class Class857 { + public Class857(){ + + } +} +class Class858 { + public Class858(){ + + } +} +class Class859 { + public Class859(){ + + } +} +class Class860 { + public Class860(){ + + } +} +class Class861 { + public Class861(){ + + } +} +class Class862 { + public Class862(){ + + } +} +class Class863 { + public Class863(){ + + } +} +class Class864 { + public Class864(){ + + } +} +class Class865 { + public Class865(){ + + } +} +class Class866 { + public Class866(){ + + } +} +class Class867 { + public Class867(){ + + } +} +class Class868 { + public Class868(){ + + } +} +class Class869 { + public Class869(){ + + } +} +class Class870 { + public Class870(){ + + } +} +class Class871 { + public Class871(){ + + } +} +class Class872 { + public Class872(){ + + } +} +class Class873 { + public Class873(){ + + } +} +class Class874 { + public Class874(){ + + } +} +class Class875 { + public Class875(){ + + } +} +class Class876 { + public Class876(){ + + } +} +class Class877 { + public Class877(){ + + } +} +class Class878 { + public Class878(){ + + } +} +class Class879 { + public Class879(){ + + } +} +class Class880 { + public Class880(){ + + } +} +class Class881 { + public Class881(){ + + } +} +class Class882 { + public Class882(){ + + } +} +class Class883 { + public Class883(){ + + } +} +class Class884 { + public Class884(){ + + } +} +class Class885 { + public Class885(){ + + } +} +class Class886 { + public Class886(){ + + } +} +class Class887 { + public Class887(){ + + } +} +class Class888 { + public Class888(){ + + } +} +class Class889 { + public Class889(){ + + } +} +class Class890 { + public Class890(){ + + } +} +class Class891 { + public Class891(){ + + } +} +class Class892 { + public Class892(){ + + } +} +class Class893 { + public Class893(){ + + } +} +class Class894 { + public Class894(){ + + } +} +class Class895 { + public Class895(){ + + } +} +class Class896 { + public Class896(){ + + } +} +class Class897 { + public Class897(){ + + } +} +class Class898 { + public Class898(){ + + } +} +class Class899 { + public Class899(){ + + } +} +class Class900 { + public Class900(){ + + } +} +class Class901 { + public Class901(){ + + } +} +class Class902 { + public Class902(){ + + } +} +class Class903 { + public Class903(){ + + } +} +class Class904 { + public Class904(){ + + } +} +class Class905 { + public Class905(){ + + } +} +class Class906 { + public Class906(){ + + } +} +class Class907 { + public Class907(){ + + } +} +class Class908 { + public Class908(){ + + } +} +class Class909 { + public Class909(){ + + } +} +class Class910 { + public Class910(){ + + } +} +class Class911 { + public Class911(){ + + } +} +class Class912 { + public Class912(){ + + } +} +class Class913 { + public Class913(){ + + } +} +class Class914 { + public Class914(){ + + } +} +class Class915 { + public Class915(){ + + } +} +class Class916 { + public Class916(){ + + } +} +class Class917 { + public Class917(){ + + } +} +class Class918 { + public Class918(){ + + } +} +class Class919 { + public Class919(){ + + } +} +class Class920 { + public Class920(){ + + } +} +class Class921 { + public Class921(){ + + } +} +class Class922 { + public Class922(){ + + } +} +class Class923 { + public Class923(){ + + } +} +class Class924 { + public Class924(){ + + } +} +class Class925 { + public Class925(){ + + } +} +class Class926 { + public Class926(){ + + } +} +class Class927 { + public Class927(){ + + } +} +class Class928 { + public Class928(){ + + } +} +class Class929 { + public Class929(){ + + } +} +class Class930 { + public Class930(){ + + } +} +class Class931 { + public Class931(){ + + } +} +class Class932 { + public Class932(){ + + } +} +class Class933 { + public Class933(){ + + } +} +class Class934 { + public Class934(){ + + } +} +class Class935 { + public Class935(){ + + } +} +class Class936 { + public Class936(){ + + } +} +class Class937 { + public Class937(){ + + } +} +class Class938 { + public Class938(){ + + } +} +class Class939 { + public Class939(){ + + } +} +class Class940 { + public Class940(){ + + } +} +class Class941 { + public Class941(){ + + } +} +class Class942 { + public Class942(){ + + } +} +class Class943 { + public Class943(){ + + } +} +class Class944 { + public Class944(){ + + } +} +class Class945 { + public Class945(){ + + } +} +class Class946 { + public Class946(){ + + } +} +class Class947 { + public Class947(){ + + } +} +class Class948 { + public Class948(){ + + } +} +class Class949 { + public Class949(){ + + } +} +class Class950 { + public Class950(){ + + } +} +class Class951 { + public Class951(){ + + } +} +class Class952 { + public Class952(){ + + } +} +class Class953 { + public Class953(){ + + } +} +class Class954 { + public Class954(){ + + } +} +class Class955 { + public Class955(){ + + } +} +class Class956 { + public Class956(){ + + } +} +class Class957 { + public Class957(){ + + } +} +class Class958 { + public Class958(){ + + } +} +class Class959 { + public Class959(){ + + } +} +class Class960 { + public Class960(){ + + } +} +class Class961 { + public Class961(){ + + } +} +class Class962 { + public Class962(){ + + } +} +class Class963 { + public Class963(){ + + } +} +class Class964 { + public Class964(){ + + } +} +class Class965 { + public Class965(){ + + } +} +class Class966 { + public Class966(){ + + } +} +class Class967 { + public Class967(){ + + } +} +class Class968 { + public Class968(){ + + } +} +class Class969 { + public Class969(){ + + } +} +class Class970 { + public Class970(){ + + } +} +class Class971 { + public Class971(){ + + } +} +class Class972 { + public Class972(){ + + } +} +class Class973 { + public Class973(){ + + } +} +class Class974 { + public Class974(){ + + } +} +class Class975 { + public Class975(){ + + } +} +class Class976 { + public Class976(){ + + } +} +class Class977 { + public Class977(){ + + } +} +class Class978 { + public Class978(){ + + } +} +class Class979 { + public Class979(){ + + } +} +class Class980 { + public Class980(){ + + } +} +class Class981 { + public Class981(){ + + } +} +class Class982 { + public Class982(){ + + } +} +class Class983 { + public Class983(){ + + } +} +class Class984 { + public Class984(){ + + } +} +class Class985 { + public Class985(){ + + } +} +class Class986 { + public Class986(){ + + } +} +class Class987 { + public Class987(){ + + } +} +class Class988 { + public Class988(){ + + } +} +class Class989 { + public Class989(){ + + } +} +class Class990 { + public Class990(){ + + } +} +class Class991 { + public Class991(){ + + } +} +class Class992 { + public Class992(){ + + } +} +class Class993 { + public Class993(){ + + } +} +class Class994 { + public Class994(){ + + } +} +class Class995 { + public Class995(){ + + } +} +class Class996 { + public Class996(){ + + } +} +class Class997 { + public Class997(){ + + } +} +class Class998 { + public Class998(){ + + } +} +class Class999 { + public Class999(){ + + } +} +class Class1000 { + public Class1000(){ + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedProducer.java new file mode 100644 index 00000000000..c9483a26bab --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedProducer.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +/** + * Garbage producer that uses another garbage producer + * to implement it's functionality. + */ +public abstract class DerivedProducer implements GarbageProducer { + private GarbageProducer

      parent; + + public DerivedProducer(GarbageProducer

      parent) { + setParent(parent); + } + + protected P createParent(long memory) { + return parent.create(memory); + } + + protected void validateParent(P obj) { + parent.validate(obj); + } + + public final GarbageProducer

      getParent() { + return parent; + } + + public final void setParent(GarbageProducer

      parent) { + this.parent = parent; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedStrategyProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedStrategyProducer.java new file mode 100644 index 00000000000..9d6834a37e1 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedStrategyProducer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +/** + * Derived garbage producer that uses a memory strategy. + */ +public abstract class DerivedStrategyProducer extends DerivedProducer { + protected MemoryStrategy memoryStrategy; + + public DerivedStrategyProducer(GarbageProducer

      parent, MemoryStrategy memoryStrategy) { + super(parent); + } + + public final void setMemoryStrategy(MemoryStrategy memoryStrategy) { + this.memoryStrategy = memoryStrategy; + } + + public final MemoryStrategy getMemoryStrategy() { + return memoryStrategy; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer.java new file mode 100644 index 00000000000..d703885a0c6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +/** + * Interface that defines a way to produce garbage. + */ +public interface GarbageProducer { + /** + * Produce garbage of given size. + * + * @param memory size in bytes + * @return produced garbage + */ + public T create(long memory); + + /** + * Validate earlier produced object. + * + * @param obj earlier produced garbage + * @throws TestFailure if validation fails + */ + public void validate(T obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer1Aware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer1Aware.java new file mode 100644 index 00000000000..e5f65c8a937 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer1Aware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +/** + * Marker interface for getting GarbageProducer. + */ +public interface GarbageProducer1Aware { + public void setGarbageProducer1(GarbageProducer gp); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducerAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducerAware.java new file mode 100644 index 00000000000..f7ef1289869 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducerAware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +/** + * Marker interface for getting GarbageProducer. + */ +public interface GarbageProducerAware { + public void setGarbageProducer(GarbageProducer gp); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducers.java new file mode 100644 index 00000000000..38169bd99a2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducers.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +import java.util.List; +import java.util.ArrayList; +import nsk.share.gc.gp.array.*; +import nsk.share.gc.gp.string.*; + +/** + * Factory for garbage producers + */ +public class GarbageProducers { + private List primitiveArrayProducers; + private List arrayProducers; + private List> stringProducers; + private List allProducers; + + /** + * Get all primitive array producers. + */ + public List getPrimitiveArrayProducers() { + if (primitiveArrayProducers == null) { + primitiveArrayProducers = new ArrayList(); + primitiveArrayProducers.add(new ByteArrayProducer()); + primitiveArrayProducers.add(new BooleanArrayProducer()); + primitiveArrayProducers.add(new ShortArrayProducer()); + primitiveArrayProducers.add(new CharArrayProducer()); + primitiveArrayProducers.add(new IntArrayProducer()); + primitiveArrayProducers.add(new LongArrayProducer()); + primitiveArrayProducers.add(new FloatArrayProducer()); + primitiveArrayProducers.add(new DoubleArrayProducer()); + } + return primitiveArrayProducers; + } + + /** + * Get all array producers. + */ + public List getArrayProducers() { + if (arrayProducers == null) { + arrayProducers = new ArrayList(); + arrayProducers.addAll(getPrimitiveArrayProducers()); + arrayProducers.add(new ObjectArrayProducer()); + } + return arrayProducers; + } + + /** + * Get all string producers. + */ + public List> getStringProducers() { + if (stringProducers == null) { + stringProducers = new ArrayList>(); + stringProducers.add(new RandomStringProducer()); + stringProducers.add(new InternedStringProducer()); + } + return stringProducers; + } + + public List getAllProducers() { + if (allProducers == null) { + allProducers = new ArrayList(); + allProducers.addAll(getArrayProducers()); + allProducers.addAll(getStringProducers()); + } + return allProducers; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java new file mode 100644 index 00000000000..333bf070b68 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.*; +import nsk.share.gc.gp.array.*; +import nsk.share.gc.gp.string.*; +import nsk.share.gc.gp.list.*; +import nsk.share.gc.gp.tree.*; +import nsk.share.gc.gp.misc.*; +import nsk.share.gc.gp.classload.*; +import nsk.share.gc.Memory; +import nsk.share.TestBug; +import nsk.share.test.*; + +/** + * Utility methods for garbage producers. + */ +public final class GarbageUtils { + private static final int ALLOCATION_LIMIT = 50000000; //50 Mb + private static GarbageProducers garbageProducers; + private static List primitiveArrayProducers; + private static List arrayProducers; + private static final GarbageProducer byteArrayProducer = new ByteArrayProducer(); + public static enum OOM_TYPE { + ANY (), + HEAP("Java heap space"), + METASPACE("Metaspace", "Compressed class space"); + + private final String[] expectedStrings; + OOM_TYPE(String... expectedStrings) { + this.expectedStrings = expectedStrings; + } + + /** + * Returns true if the given error message matches + * one of expected strings. + */ + public boolean accept(String errorMessage) { + if (expectedStrings == null || expectedStrings.length == 0 || errorMessage == null) { + return true; + } + for (String s: expectedStrings) { + if (errorMessage.indexOf(s) != -1) { + return true; + } + } + return false; + } + }; + + // Force loading of OOM_TYPE and calling of enum contrusctors when loading GarbageUtils class. + public static final Object[] thisIsGarbageArray_theOnlyPurposeForCreatingItAndDeclaringItPublicIsToInitializeIntancesOfOOMEnumberation = new Object[] { OOM_TYPE.ANY, OOM_TYPE.HEAP, OOM_TYPE.METASPACE }; + + // Force early loading of classes that might otherwise unexpectedly fail + // class loading during testing due to high memory pressure. + public static final StringWriter preloadStringWriter = new StringWriter(1); + public static final PrintWriter preloadPrintWriter = new PrintWriter(preloadStringWriter); + + private GarbageUtils() { + } + + /** + * Eat memory using execution controller that waits for 2 minutes. + * @return number of OOME occured + */ + public static int eatMemory() { + return eatMemory(2 * 60 * 1000); + } + + /** + * Eat memory using execution controller that waits for timeout. + * @return number of OOME occured + */ + public static int eatMemory(final long timeout) { + return eatMemory(new ExecutionController() { + final long initialTime = System.currentTimeMillis(); + + @Override + public void start(long stdIterations) {} + + @Override + public boolean iteration() {return false;} + + @Override + public boolean continueExecution() { + return System.currentTimeMillis() - initialTime < timeout; + } + + @Override + public long getIteration() {return 0;} + + @Override + public void finish() {} + }); + } + + + /** + * Eat memory using given execution controller and garbage producer. + * + * @param stresser execution controller + * @param gp garbage producer + * @return number of OOME occured + */ + public static int eatMemory(ExecutionController stresser) { + return eatMemory(stresser, byteArrayProducer, 50, 100, 2, OOM_TYPE.ANY); + } + + /** + * Eat memory using given execution controller and garbage producer. + * + * @param stresser execution controller + * @param gp garbage producer + * @return number of OOME occured + */ + public static int eatMemory(ExecutionController stresser, GarbageProducer gp) { + return eatMemory(stresser, gp, 50, 100, 2, OOM_TYPE.ANY); + } + + /** + * Eat memory using given garbage producer and given factor. + * + * @param gp garbage producer + * @param factor factor to divide the array size by + * @return number of OOME occured + */ + public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long factor) { + return eatMemory(stresser, gp, 50, 100, factor, OOM_TYPE.ANY); + } + + /** + * Eat memory using default(byte[]) garbage producer. + * + * Note that this method can throw Failure if any exception + * is thrown while eating memory. To avoid OOM while allocating + * exception we preallocate it before the lunch starts. It means + * that exception stack trace does not correspond to the place + * where exception is thrown, but points at start of the method. + * + * @param stresser stresser + * @param initialFactor determines which portion of initial memory initial chunk will be + * @param minMemoryChunk determines when to stop + * @param factor factor to divide the array size by + * @return number of OOME occured + */ + public static int eatMemory(ExecutionController stresser,long initialFactor, long minMemoryChunk, long factor) { + return eatMemory(stresser, byteArrayProducer, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY); + } + + /** + * Eat memory using given garbage producer. + * + * Note that this method can throw Failure if any exception + * is thrown while eating memory. To avoid OOM while allocating + * exception we preallocate it before the lunch starts. It means + * that exception stack trace does not correspond to the place + * where exception is thrown, but points at start of the method. + * + * @param stresser stresser to use + * @param gp garbage producer + * @param initialFactor determines which portion of initial memory initial chunk will be + * @param minMemoryChunk determines when to stop + * @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME + * @param type of OutOfMemory Exception: Java heap space or Metadata space + * @return number of OOME occured + */ + public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor) { + return eatMemory(stresser, gp, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY); + } + + /** + * Eat memory using given garbage producer. + * + * Note that this method can throw Failure if any exception + * is thrown while eating memory. To avoid OOM while allocating + * exception we preallocate it before the lunch starts. It means + * that exception stack trace does not correspond to the place + * where exception is thrown, but points at start of the method. + * + * @param stresser stresser to use + * @param gp garbage producer + * @param initialFactor determines which portion of initial memory initial chunk will be + * @param minMemoryChunk determines when to stop + * @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME + * @param type of OutOfMemory Exception: Java heap space or Metadata space + * @return number of OOME occured + */ + public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) { + int numberOfOOMEs = 0; + try { + StringWriter sw = new StringWriter(10000); + PrintWriter pw = new PrintWriter(sw); + byte[] someMemory = new byte[200000]; //200 Kb + try { + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + long maxMemoryChunk = maxMemory / initialFactor; + long chunk = maxMemoryChunk; + chunk = chunk > ALLOCATION_LIMIT ? ALLOCATION_LIMIT : chunk; + int allocations = 0; + List storage = new ArrayList(); + + while (chunk > minMemoryChunk && stresser.continueExecution()) { + try { + storage.add(gp.create(chunk)); + if (Thread.currentThread().isInterrupted()) { + return numberOfOOMEs; + } + // if we are able to eat chunk*factor let + // try to increase size of chunk + if (chunk * factor < maxMemoryChunk + && factor != 0 && allocations++ == factor + 1) { + chunk = chunk * factor; + allocations = 0; + } + } catch (OutOfMemoryError e) { + someMemory = null; + if (type != OOM_TYPE.ANY) { + e.printStackTrace(pw); + pw.close(); + if (type.accept(sw.toString())) { + numberOfOOMEs++; + } else { + // Trying to catch situation when Java generates OOM different type that test trying to catch + throw new TestBug("Test throw OOM of unexpected type." + sw.toString()); + } + } else { + numberOfOOMEs++; + } + allocations = 0; + if (factor == 0) { + return numberOfOOMEs; + } else { + chunk = chunk / factor; + } + } + } + } catch (OutOfMemoryError e) { + someMemory = null; + if (type != OOM_TYPE.ANY) { + e.printStackTrace(pw); + pw.close(); + if (type.accept(sw.toString())) { + numberOfOOMEs++; + } else { + // Trying to catch situation when Java generates OOM different type that test trying to catch + throw new TestBug("Test throw OOM of unexpected type." + sw.toString()); + } + } else { + numberOfOOMEs++; + } + // all memory is eaten now even before we start, just return + } + } catch (OutOfMemoryError e) { + numberOfOOMEs++; + } + return numberOfOOMEs; + } + + /** + * Get all primitive array producers. + */ + public static List getPrimitiveArrayProducers() { + return getGarbageProducers().getPrimitiveArrayProducers(); + } + + /** + * Get all array producers. + */ + public static List getArrayProducers() { + return getGarbageProducers().getArrayProducers(); + } + + /** + * Determine size of each object in array which will occupy given + * memory with distribution determined by given memory strategy. + */ + public static long getArraySize(long memory, MemoryStrategy memoryStrategy) { + return memoryStrategy.getSize(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize()); + } + + /** + * Determine object count in array which will occupy given + * memory with distribution determined by given memory strategy. + */ + public static int getArrayCount(long memory, MemoryStrategy memoryStrategy) { + return memoryStrategy.getCount(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize()); + } + + /** + * Get garbage producer by identifier. + * + * @param id identifier + * @return garbage producer for this identifier + */ + public static GarbageProducer getGarbageProducer(String id) { + if (id == null || id.equals("byteArr")) + return new ByteArrayProducer(); + else if (id.equals("booleanArr")) + return new BooleanArrayProducer(); + else if (id.equals("shortArr")) + return new ShortArrayProducer(); + else if (id.equals("charArr")) + return new CharArrayProducer(); + else if (id.equals("intArr")) + return new IntArrayProducer(); + else if (id.equals("longArr")) + return new LongArrayProducer(); + else if (id.equals("floatArr")) + return new FloatArrayProducer(); + else if (id.equals("doubleArr")) + return new DoubleArrayProducer(); + else if (id.equals("objectArr")) + return new ObjectArrayProducer(); + else if (id.equals("randomString")) + return new RandomStringProducer(); + else if (id.equals("simpleString")) + return new SimpleStringProducer(); + else if (id.startsWith("interned(")) + return new InternedStringProducer(getGarbageProducer(getInBrackets(id))); + else if (id.startsWith("linearList(")) + return new LinearListProducer(MemoryStrategy.fromString(getInBrackets(id))); + else if (id.startsWith("circularList(")) + return new CircularListProducer(MemoryStrategy.fromString(getInBrackets(id))); + else if (id.startsWith("nonbranchyTree(")) + return new NonbranchyTreeProducer(MemoryStrategy.fromString(getInBrackets(id))); + else if (id.equals("class")) + return new GeneratedClassProducer(); + else if (id.startsWith("hashed(")) + return new HashedGarbageProducer(getGarbageProducer(getInBrackets(id))); + else if (id.startsWith("random(")) + return new RandomProducer(getGarbageProducerList(getInBrackets(id))); + else if (id.startsWith("twofields(")) + return new TwoFieldsObjectProducer(getGarbageProducer(getInBrackets(id))); + else if (id.startsWith("arrayof(")) + return new ArrayOfProducer(getGarbageProducer(getInBrackets(id))); + else if (id.startsWith("trace(")) + return new TraceProducer(getGarbageProducer(getInBrackets(id))); + else + throw new TestBug("Invalid garbage producer identifier: " + id); + } + + private static String getInBrackets(String s) { + int n1 = s.indexOf('('); + if (n1 == -1) + throw new TestBug("Opening bracket not found: " + s); + int n2 = s.lastIndexOf(')'); + if (n2 == -1) + throw new TestBug("Closing bracket not found: " + s); + return s.substring(n1 + 1, n2); + } + + private static List getGarbageProducerList(String s) { + if (s.equals("primitiveArrays")) + return getPrimitiveArrayProducers(); + else if (s.equals("arrays")) + return getArrayProducers(); + else { + String[] ids = s.split(","); + List garbageProducers = new ArrayList(ids.length); + for (int i = 0; i < ids.length; ++i) + garbageProducers.add(getGarbageProducer(ids[i])); + return garbageProducers; + //throw new TestBug("Invalid id for list of garbage producers: " + id); + } + } + + public static GarbageProducers getGarbageProducers() { + if (garbageProducers == null) + garbageProducers = new GarbageProducers(); + return garbageProducers; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategy.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategy.java new file mode 100644 index 00000000000..4afaf11fb77 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategy.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +import nsk.share.TestBug; + +/** + * This class encapsulates notions like "many objects of small size", + * "small number of objects of big size". + */ +public abstract class MemoryStrategy { + private static int smallNumber = 100; + public abstract long getSize(long memory); + public abstract long getSize(long memory, long objectExtra); + public abstract int getCount(long memory); + public abstract int getCount(long memory, long objectExtra); + + protected MemoryStrategy() { + } + + /** + * Small object size, big number of objects. + */ + public static final MemoryStrategy LOW = new MemoryStrategy() { + public long getSize(long memory) { + return getSize(memory, 0); + } + + public long getSize(long memory, long objectExtra) { + return smallNumber; + } + + public int getCount(long memory) { + return getCount(memory, 0); + } + + public int getCount(long memory, long objectExtra) { + return (int) Math.min(Integer.MAX_VALUE, memory / (getSize(memory) + objectExtra)); + } + + public String toString() { + return "low"; + } + }; + + /** + * Medium object size, medium number of objects. + */ + public static final MemoryStrategy MEDIUM = new MemoryStrategy() { + public long getSize(long memory) { + return getSize(memory, 0); + } + + public long getSize(long memory, long objectExtra) { + return Math.round(Math.floor(Math.sqrt(memory))); + } + + public int getCount(long memory) { + return getCount(memory, 0); + } + + public int getCount(long memory, long objectExtra) { + return (int) Math.min(Integer.MAX_VALUE, memory / (getSize(memory) + objectExtra)); + } + + public String toString() { + return "medium"; + } + }; + + /** + * Big object size, small number of objects. + */ + public static final MemoryStrategy HIGH = new MemoryStrategy() { + public long getSize(long memory) { + return getSize(memory, 0); + } + + public long getSize(long memory, long objectExtra) { + return memory / getCount(memory, objectExtra); + } + + public int getCount(long memory) { + return getCount(memory, 0); + } + + public int getCount(long memory, long objectExtra) { + return smallNumber; + } + + public String toString() { + return "high"; + } + }; + + /** + * Get memory strategy by identifier. + * + * @param id identifier + * @return memory strategy for this identifier + * @throws TestBug if id is invalid + */ + public static MemoryStrategy fromString(String id) { + if (id.equalsIgnoreCase("low")) + return LOW; + else if (id.equalsIgnoreCase("medium")) + return MEDIUM; + else if (id.equalsIgnoreCase("high")) + return HIGH; + else + throw new TestBug("Unknown memory strategy identifier: " + id); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategyAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategyAware.java new file mode 100644 index 00000000000..22a4755aa34 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategyAware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +/** + * Marker interface for getting MemoryStrategy. + */ +public interface MemoryStrategyAware { + public void setMemoryStrategy(MemoryStrategy memoryStrategy); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/RandomProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/RandomProducer.java new file mode 100644 index 00000000000..0200856eeff --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/RandomProducer.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp; + +import java.util.List; +import nsk.share.test.LocalRandom; + +/** + * Garbage producer that randomly creates objects using + * one garbage producer from the list. + */ +public class RandomProducer implements GarbageProducer { + private List> producers; + + public RandomProducer(List> producers) { + this.producers = producers; + } + + public T create(long memory) { + return producers.get(LocalRandom.nextInt(producers.size())).create(memory); + } + + public void validate(T obj) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayOfProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayOfProducer.java new file mode 100644 index 00000000000..5df59b2d969 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayOfProducer.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.gp.DerivedProducer; +import nsk.share.gc.gp.GarbageUtils; +import nsk.share.gc.gp.MemoryStrategy; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces arrays of objects + * determined by parent garbage producer. A memory strategy is + * used to determine how memory is distributed between array size + * and size of each object in array. + */ +public class ArrayOfProducer extends DerivedProducer { + private int n; + + public ArrayOfProducer(GarbageProducer parent, int n) { + super(parent); + this.n = n; + } + + public ArrayOfProducer(GarbageProducer parent) { + this(parent, 2); + } + + public Object[] create(long memory) { + Object[] array = new Object[n]; + long objectSize = (memory - Memory.getArrayExtraSize() - Memory.getReferenceSize() * n) / n; + for (int i = 0; i < n; ++i) + array[i] = createParent(objectSize); + return array; + } + + public void validate(Object[] obj) { + for (int i = 0; i < obj.length; ++i) + validateParent((T) obj[i]); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayProducer.java new file mode 100644 index 00000000000..5182bb894b0 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayProducer.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.gp.DerivedStrategyProducer; +import nsk.share.gc.gp.GarbageUtils; +import nsk.share.gc.gp.MemoryStrategy; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces arrays of objects + * determined by parent garbage producer. A memory strategy is + * used to determine how memory is distributed between array size + * and size of each object in array. + */ +public class ArrayProducer extends DerivedStrategyProducer { + public ArrayProducer(GarbageProducer parent, MemoryStrategy memoryStrategy) { + super(parent, memoryStrategy); + } + + public Object[] create(long memory) { + long objectSize = GarbageUtils.getArraySize(memory, memoryStrategy); + int objectCount = GarbageUtils.getArrayCount(memory, memoryStrategy); + Object[] array = new Object[objectCount]; + for (int i = 0; i < objectCount; ++i) + array[i] = createParent(objectSize); + return array; + } + + public void validate(Object[] obj) { + for (int i = 0; i < obj.length; ++i) + validateParent((T) obj[i]); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/BooleanArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/BooleanArrayProducer.java new file mode 100644 index 00000000000..d0665e8044a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/BooleanArrayProducer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces byte arrays. + */ +public class BooleanArrayProducer implements GarbageProducer { + public boolean[] create(long memory) { + boolean[] arr = new boolean[Memory.getArrayLength(memory, Memory.getBooleanSize())]; + LocalRandom.nextBooleans(arr); + return arr; + } + + public void validate(boolean[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ByteArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ByteArrayProducer.java new file mode 100644 index 00000000000..2469e371192 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ByteArrayProducer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces byte arrays. + */ +public class ByteArrayProducer implements GarbageProducer { + public byte[] create(long memory) { + byte[] arr = new byte[Memory.getArrayLength(memory, 1)]; + LocalRandom.nextBytes(arr); + return arr; + } + + public void validate(byte[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/CharArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/CharArrayProducer.java new file mode 100644 index 00000000000..95db54db286 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/CharArrayProducer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces int arrays. + */ +public class CharArrayProducer implements GarbageProducer { + public char[] create(long memory) { + char[] arr = new char[Memory.getArrayLength(memory, Memory.getCharSize())]; + LocalRandom.nextChars(arr); + return arr; + } + + public void validate(char[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/DoubleArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/DoubleArrayProducer.java new file mode 100644 index 00000000000..4735434f402 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/DoubleArrayProducer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; + +/** + * GarbageProducer implementation that produces double arrays. + */ +public class DoubleArrayProducer implements GarbageProducer { + public double[] create(long memory) { + double[] arr = new double[Memory.getArrayLength(memory, Memory.getDoubleSize())]; + LocalRandom.nextDoubles(arr); + return arr; + } + + public void validate(double[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/FloatArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/FloatArrayProducer.java new file mode 100644 index 00000000000..4fc1f435f73 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/FloatArrayProducer.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; + +/** + * GarbageProducer implementation that produces float arrays. + */ +public class FloatArrayProducer implements GarbageProducer { + public float[] create(long memory) { + float[] arr = new float[Memory.getArrayLength(memory, Memory.getFloatSize())]; + LocalRandom.nextFloats(arr); + return arr; + } + + public void validate(float[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/IntArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/IntArrayProducer.java new file mode 100644 index 00000000000..cae41f92e33 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/IntArrayProducer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces int arrays. + */ +public class IntArrayProducer implements GarbageProducer { + public int[] create(long memory) { + int[] arr = new int[Memory.getArrayLength(memory, Memory.getIntSize())]; + LocalRandom.nextInts(arr); + return arr; + } + + public void validate(int[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/LongArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/LongArrayProducer.java new file mode 100644 index 00000000000..7753664cee8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/LongArrayProducer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces long arrays. + */ +public class LongArrayProducer implements GarbageProducer { + public long[] create(long memory) { + long[] arr = new long[Memory.getArrayLength(memory, Memory.getLongSize())]; + LocalRandom.nextLongs(arr); + return arr; + } + + public void validate(long[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ObjectArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ObjectArrayProducer.java new file mode 100644 index 00000000000..710b8494fde --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ObjectArrayProducer.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; + +/** + * GarbageProducer implementation that produces object arrays. + */ +public class ObjectArrayProducer implements GarbageProducer { + public Object[] create(long memory) { + return new Object[Memory.getArrayLength(memory, Memory.getObjectExtraSize())]; + } + + public void validate(Object[] arr) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ShortArrayProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ShortArrayProducer.java new file mode 100644 index 00000000000..026ff72a595 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ShortArrayProducer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.array; + +import nsk.share.test.LocalRandom; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.Memory; +import nsk.share.TestFailure; + +/** + * GarbageProducer implementation that produces short arrays. + */ +public class ShortArrayProducer implements GarbageProducer { + public short[] create(long memory) { + short[] arr = new short[Memory.getArrayLength(memory, Memory.getShortSize())]; + LocalRandom.nextShorts(arr); + return arr; + } + + public void validate(short[] arr) { + LocalRandom.validate(arr); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/classload/GeneratedClassProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/classload/GeneratedClassProducer.java new file mode 100644 index 00000000000..acd830a02be --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/classload/GeneratedClassProducer.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.classload; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.classload.GeneratingClassLoader; +import nsk.share.classload.GeneratingClassLoader; +import nsk.share.gc.gp.GarbageUtils; +import nsk.share.test.LocalRandom; + +/** + * Garbage producer that creates classes loaded with GeneratingClassLoader. + * + * Note: this class is not thread-safe. + */ +public class GeneratedClassProducer implements GarbageProducer { + private int number; + private String className; + private StringBuilder sb = new StringBuilder(); + private int minPerClassLoader = 50; + private int maxPerClassLoader = 150; + private int count; + private GeneratingClassLoader loader = new GeneratingClassLoader(); + + public GeneratedClassProducer() { + this(GeneratingClassLoader.DEFAULT_CLASSNAME); + } + + public GeneratedClassProducer(String className) { + this.className = className; + } + + private String getNewName() { + sb.delete(0, sb.length()); + sb.append("Class"); + sb.append(number); + int n = loader.getNameLength() - sb.length(); + for (int i = 0; i < n; ++i) + sb.append('_'); + return sb.toString(); + } + + public Class create(long memory) { + try { + if (number++ > maxPerClassLoader || loader == null) { + loader = new GeneratingClassLoader(className); + count = LocalRandom.nextInt(minPerClassLoader, maxPerClassLoader); + number = 0; + } + return loader.loadClass(getNewName()); + } catch (ClassNotFoundException e) { + throw convertException(e); + } + } + + public void validate(Class cl) { + } + + protected RuntimeException convertException(Exception e) { + return new RuntimeException(e); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/CircularListProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/CircularListProducer.java new file mode 100644 index 00000000000..1f54b97ed55 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/CircularListProducer.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.list; + +import nsk.share.gc.LinkedMemoryObject; +import nsk.share.gc.Memory; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.gp.MemoryStrategy; + +/** + * Garbage producer that produces circular linked lists. + */ +public class CircularListProducer implements GarbageProducer { + private MemoryStrategy memoryStrategy; + + public CircularListProducer(MemoryStrategy memoryStrategy) { + this.memoryStrategy = memoryStrategy; + } + + public LinkedMemoryObject create(long memory) { + long objectSize = memoryStrategy.getSize(memory); + int objectCount = memoryStrategy.getCount(memory); + return Memory.makeCircularList(objectCount, (int) objectSize); + } + + public void validate(LinkedMemoryObject obj) { + LinkedMemoryObject o = obj; + while (o != null && o != obj) + o = o.getNext(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/LinearListProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/LinearListProducer.java new file mode 100644 index 00000000000..f23b0e7e7e9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/LinearListProducer.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.list; + +import nsk.share.gc.LinkedMemoryObject; +import nsk.share.gc.Memory; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.gp.MemoryStrategy; + +/** + * Garbage producer that produces linear linked lists. + */ +public class LinearListProducer implements GarbageProducer { + private MemoryStrategy memoryStrategy; + + public LinearListProducer(MemoryStrategy memoryStrategy) { + this.memoryStrategy = memoryStrategy; + } + + public LinkedMemoryObject create(long memory) { + long objectSize = memoryStrategy.getSize(memory); + int objectCount = memoryStrategy.getCount(memory); + return Memory.makeLinearList(objectCount, (int) objectSize); + } + + public void validate(LinkedMemoryObject obj) { + LinkedMemoryObject o = obj; + while (o != null && o != obj) + o = o.getNext(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java new file mode 100644 index 00000000000..db24db8b9a7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.misc; + +import nsk.share.gc.gp.DerivedProducer; +import nsk.share.gc.gp.GarbageProducer; + +/* + * Garbage producer that also calls {@link java.lang.System#identityHashCode(java.lang.Object)} on produced object. + */ + +/* + The description is misleading. I looked at some old email, and the + goal is to stress the code that deals with displaced mark words, so + the description should be more like "Stress tests for displaced mark + words." In hotspot, each object has a mark word that stores several + things about the object including its hash code (if it has one) and + lock state. Most objects never have a hash code and are never locked, + so the mark word is empty. + + Most of our garbage collectors use the mark word temporarily during GC + to store a 'forwarding pointer.' It's not important what that is, but + it means that objects that have a hash code or that are locked have to + have the mark word saved during GC and then restored at the end of GC. + We want to exercise this saving/restoring code. So a test case should + have a large percentage (40-50%) of objects that either have a hash + code or are locked. + + */ +public class HashedGarbageProducer extends DerivedProducer { + public HashedGarbageProducer(GarbageProducer parent) { + super(parent); + } + + public T create(long memory) { + T obj = createParent(memory); + System.identityHashCode(obj); + return obj; + } + + public void validate(T obj) { + validateParent(obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TraceProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TraceProducer.java new file mode 100644 index 00000000000..af96e831f61 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TraceProducer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.misc; + +import nsk.share.gc.gp.DerivedProducer; +import nsk.share.gc.gp.GarbageProducer; + +/* + * GarbageProducer that traces the production. + */ +public class TraceProducer extends DerivedProducer { + private String prid; + + public TraceProducer(GarbageProducer parent) { + super(parent); + prid = "Create (" + parent + "): "; + } + + public T create(long memory) { + T obj = createParent(memory); + System.out.println(prid + memory); + return obj; + } + + public void validate(T obj) { + validateParent(obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TwoFieldsObjectProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TwoFieldsObjectProducer.java new file mode 100644 index 00000000000..d02ba08d3b1 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TwoFieldsObjectProducer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.gc.gp.misc; + +import nsk.share.gc.Memory; +import nsk.share.gc.*; +import nsk.share.gc.gp.*; + +/** + * GarbageProducer that produces object with two fields which + * reference objects producer by parent garbage producer. + */ +public class TwoFieldsObjectProducer extends DerivedProducer, T> { + public TwoFieldsObjectProducer(GarbageProducer parent) { + super(parent); + } + + public TwoFieldsObject create(long memory) { + long memoryT = (memory - Memory.getObjectExtraSize() - 2 * Memory.getReferenceSize()) / 2; + return new TwoFieldsObject(createParent(memoryT), createParent(memoryT)); + } + + public void validate(TwoFieldsObject obj) { + validateParent(obj.getLeft()); + validateParent(obj.getRight()); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/AllMemoryObjectProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/AllMemoryObjectProducer.java new file mode 100644 index 00000000000..a7742624c7e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/AllMemoryObjectProducer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.obj; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.AllMemoryObject; + +public class AllMemoryObjectProducer implements GarbageProducer { + public AllMemoryObject create(long memory) { + return new AllMemoryObject((int) memory); + } + + public void validate(AllMemoryObject obj) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObject1Producer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObject1Producer.java new file mode 100644 index 00000000000..c5d75824d82 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObject1Producer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.obj; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.FinMemoryObject1; + +public class FinMemoryObject1Producer implements GarbageProducer { + public FinMemoryObject1 create(long memory) { + return new FinMemoryObject1((int) memory); + } + + public void validate(FinMemoryObject1 obj) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObjectProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObjectProducer.java new file mode 100644 index 00000000000..1fc93f979e3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObjectProducer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.obj; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.FinMemoryObject; + +public class FinMemoryObjectProducer implements GarbageProducer { + public FinMemoryObject create(long memory) { + return new FinMemoryObject((int) memory); + } + + public void validate(FinMemoryObject obj) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/MemoryObjectProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/MemoryObjectProducer.java new file mode 100644 index 00000000000..6ece69c9c34 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/MemoryObjectProducer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.obj; + +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.MemoryObject; + +public class MemoryObjectProducer implements GarbageProducer { + public MemoryObject create(long memory) { + return new MemoryObject((int) memory); + } + + public void validate(MemoryObject obj) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/InternedStringProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/InternedStringProducer.java new file mode 100644 index 00000000000..8d6986d3983 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/InternedStringProducer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.string; + +import nsk.share.gc.gp.DerivedProducer; +import nsk.share.gc.gp.GarbageProducer; + +/** + * Garbage producer that creates interned strings. + */ +public class InternedStringProducer extends DerivedProducer { + public InternedStringProducer() { + this(new RandomStringProducer()); + } + + public InternedStringProducer(GarbageProducer parent) { + super(parent); + } + + public String create(long memory) { + return createParent(memory).intern(); + } + + public void validate(String s) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/RandomStringProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/RandomStringProducer.java new file mode 100644 index 00000000000..2291b3b539f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/RandomStringProducer.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.gc.gp.string; + +import nsk.share.test.*; +import nsk.share.gc.Memory; +import nsk.share.gc.gp.GarbageProducer; + +/** + * Garbage producer that creates random strings. + */ +public class RandomStringProducer implements GarbageProducer { + + private int stringLengthLowerBound = 10; + + public RandomStringProducer() { + } + + public RandomStringProducer(int stringLengthLowerBound) { + this.stringLengthLowerBound = stringLengthLowerBound; + } + + public String create(long memory) { + int stringLengthUpperBound = (int) Math.min(memory / 2 - Memory.getObjectExtraSize(), Integer.MAX_VALUE); + if (stringLengthUpperBound < stringLengthLowerBound) { + stringLengthLowerBound = stringLengthUpperBound; + } + int length = stringLengthLowerBound + LocalRandom.nextInt(stringLengthUpperBound - stringLengthLowerBound); + char[] arr = new char[length]; + for (int i = 0; i < length; ++i) { + arr[i] = (char) LocalRandom.nextInt(); + } + return new String(arr); + } + + public void setStringLengthLowerBound(int stringLengthLowerBound) { + this.stringLengthLowerBound = stringLengthLowerBound; + } + + public void validate(String s) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/SimpleStringProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/SimpleStringProducer.java new file mode 100644 index 00000000000..c6e4e8fe3ef --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/SimpleStringProducer.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.string; + +import nsk.share.test.*; +import nsk.share.gc.gp.GarbageProducer; + +/** + * Garbage producer that creates simple strings. + */ +public class SimpleStringProducer implements GarbageProducer { + + + public String create(long memory) { + long length = memory/8; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; ++i) + sb.append((char) LocalRandom.nextInt()); + return sb.toString(); + } + + + public void validate(String s) { + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/tree/NonbranchyTreeProducer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/tree/NonbranchyTreeProducer.java new file mode 100644 index 00000000000..a966ce75d2d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/tree/NonbranchyTreeProducer.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.gp.tree; + +import nsk.share.gc.*; +import nsk.share.gc.gp.*; +import nsk.share.gc.Memory; + +public class NonbranchyTreeProducer implements GarbageProducer, MemoryStrategyAware { + private MemoryStrategy memoryStrategy; + private float branchiness; + + public NonbranchyTreeProducer(MemoryStrategy memoryStrategy) { + this(memoryStrategy, 0.75f); + } + + public NonbranchyTreeProducer(MemoryStrategy memoryStrategy, float branchiness) { + setMemoryStrategy(memoryStrategy); + setBranchiness(branchiness); + } + + public LinkedMemoryObject create(long memory) { + long objectSize = memoryStrategy.getSize(memory); + int objectCount = memoryStrategy.getCount(memory); + return Memory.makeNonbranchyTree(objectCount, branchiness, (int) objectSize); + } + + public void validate(LinkedMemoryObject obj) { + } + + public final void setMemoryStrategy(MemoryStrategy memoryStrategy) { + this.memoryStrategy = memoryStrategy; + } + + public final void setBranchiness(float branchiness) { + this.branchiness = branchiness; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionLocker.java new file mode 100644 index 00000000000..e909a742f44 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionLocker.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Locker; + +/** + * CriticalSectionLocker represents a way to lock a resource + * by entering some critical section. + */ +public abstract class CriticalSectionLocker implements Locker { + private transient boolean enabled = false; + private transient boolean locked = false; + private Object sync = new Object(); + private Thread thread; + private Throwable exception; + + private final Runnable runnable = new Runnable() { + public void run() { + //System.out.println("Running"); + try { + do { + synchronized (sync) { + while (enabled && !locked) { + try { + sync.wait(); + } catch (InterruptedException e) { + } + } + if (!enabled) + break; + } + do { + criticalSection(); + } while (locked); + } while (enabled); + // System.out.println("Exiting"); + } catch (RuntimeException t) { + t.printStackTrace(); + exception = t; + throw t; + } + } + }; + + public CriticalSectionLocker() { + } + + /** + * Enter critical section. + * + */ + protected abstract void criticalSection(); + + public void enable() { + synchronized (sync) { + if (enabled) + throw new TestBug("Locker already enabled."); +// System.out.println("Enabling " + this); + enabled = true; + thread = new Thread(runnable, "Locker: " + runnable); + thread.setDaemon(true); + thread.start(); + } + } + + public void lock() { + synchronized (sync) { + if (locked) + throw new TestBug("Locker already locked."); +// System.out.println("Locking " + this); + locked = true; + sync.notifyAll(); + } + } + + public void unlock() { + synchronized (sync) { + if (!locked) + throw new TestBug("Locker not locked."); +// System.out.println("Unocking " + this); + locked = false; + sync.notifyAll(); + } + } + + public void disable() { + synchronized (sync) { + if (!enabled) + throw new TestBug("Locker not enabled."); +// System.out.println("Disabling " + this); + enabled = false; + sync.notifyAll(); + } + try { + thread.join(); + } catch (InterruptedException e) { + throw new TestBug(e); + } + } + + public Throwable getException() { + return exception; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionObjectLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionObjectLocker.java new file mode 100644 index 00000000000..2a92a5f93e0 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionObjectLocker.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import nsk.share.TestBug; +import nsk.share.gc.gp.GarbageProducer; +import nsk.share.gc.gp.DerivedProducer; + +/** + * CriticalSectionLocker represents a way to lock + * a resource by entering some critical section of + * code. + */ +public abstract class CriticalSectionObjectLocker extends CriticalSectionTimedLocker implements Locker { + public T obj; + + public CriticalSectionObjectLocker(T obj) { + this.obj = obj; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionTimedLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionTimedLocker.java new file mode 100644 index 00000000000..b0d63f05dc4 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionTimedLocker.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Locker; + +/** + * CriticalSectionTimedLocker represents a way to lock a resource + * by entering some critical section for some time. + */ +public abstract class CriticalSectionTimedLocker extends CriticalSectionLocker { + private long enterTime; + private long sleepTime; + + public CriticalSectionTimedLocker() { + this(5000, 10); + } + + public CriticalSectionTimedLocker(long enterTime, long sleepTime) { + setEnterTime(enterTime); + setSleepTime(sleepTime); + } + + protected final void criticalSection() { + criticalSection(enterTime, sleepTime); + } + + /** + * Enter critical section for enterTime. + * + * Usually, something is done in a loop inside this critical section. + * In this case, sleepTime is time to sleep after each iteration. + */ + protected abstract void criticalSection(long enterTime, long sleepTime); + + public final void setEnterTime(long enterTime) { + this.enterTime = enterTime; + } + + public final void setSleepTime(long sleepTime) { + this.sleepTime = sleepTime; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Locker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Locker.java new file mode 100644 index 00000000000..f6996e8975f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Locker.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import nsk.share.gc.gp.GarbageProducer; + +/** + * Locker represents a way to lock a resource + * which may be critical for GC to work. + */ +public interface Locker { + /** + * Enable this locker and make necessary preparations. + */ + public void enable(); + + /** + * Lock an object. + * + * There can be multiple calls to this, but to lock + * again, one must first unlock. + */ + public void lock(); + + /** + * Unlock an object. + * + */ + public void unlock(); + + /** + * Get any exceptions that occured. + * + * @return exception or null if there none + */ + public Throwable getException(); + + /** + * Disable this locker and make necessary cleanups. + */ + public void disable(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockerUtils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockerUtils.java new file mode 100644 index 00000000000..503479a25ca --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockerUtils.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import nsk.share.TestBug; +import nsk.share.gc.lock.jni.JNILockers; +import nsk.share.gc.lock.malloc.MallocLockers; +import nsk.share.gc.lock.jvmti.JVMTIAllocLockers; +import nsk.share.gc.lock.jniref.*; + +/** + * Utility methods for lockers. + */ +public class LockerUtils { + private LockerUtils() { + } + + /** + * Obtain Lockers by id. + * + * @param id identifier of Lockers + */ + public static Lockers getLockers(String id) { + if (id == null || id.equals("jni")) + return new JNILockers(); + else if (id.equals("jniGlobalRef")) + return new JNIGlobalRefLockers(); + else if (id.equals("jniLocalRef")) + return new JNILocalRefLockers(); + else if (id.equals("jniRef")) + return new JNIRefLockers(); + else if (id.equals("jniWeakGlobalRef")) + return new JNIWeakGlobalRefLockers(); + else if (id.equals("malloc")) + return new MallocLockers(); + else if (id.equals("jvmtiAlloc")) + return new JVMTIAllocLockers(); + else + throw new TestBug("Invalid lockers id: " + id); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Lockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Lockers.java new file mode 100644 index 00000000000..a2349df8c1e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Lockers.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import nsk.share.gc.gp.GarbageProducer; + +public interface Lockers { + public Locker createLocker(T obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockersAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockersAware.java new file mode 100644 index 00000000000..7ce89ee6631 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockersAware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +/** + * Marker interface for getting Locker. + */ +public interface LockersAware { + public void setLockers(Lockers locker); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/MultiLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/MultiLocker.java new file mode 100644 index 00000000000..c5c8333af77 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/MultiLocker.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock; + +import java.util.List; +import java.util.ArrayList; + +/** + * MultiLocker is just a locker that uses several lockers. + */ +public class MultiLocker implements Locker { + private List> lockers; + + public MultiLocker() { + this(new ArrayList>()); + } + + public MultiLocker(List> lockers) { + this.lockers = lockers; + } + + public void enable() { + for (Locker locker : lockers) + locker.enable(); + } + + public void lock() { + for (Locker locker : lockers) + locker.lock(); + } + + public void unlock() { + for (Locker locker : lockers) + locker.unlock(); + } + + public Throwable getException() { + return null; + } + + public void disable() { + for (Locker locker : lockers) + locker.disable(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.c new file mode 100644 index 00000000000..244bc2e3b32 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_BooleanArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jboolean JNICALL Java_nsk_share_gc_lock_jni_BooleanArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jbooleanArray arr; + jboolean *pa; + jboolean hash = JNI_TRUE; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return JNI_FALSE; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return JNI_FALSE; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = JNI_FALSE; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.java new file mode 100644 index 00000000000..ef3af17ffdf --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class BooleanArrayCriticalLocker extends CriticalSectionObjectLocker { + private native boolean criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("BooleanArrayCriticalLocker"); + } + + public BooleanArrayCriticalLocker(boolean[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + boolean javaHash = hashValue(obj); + boolean nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private boolean hashValue(boolean[] obj) { + boolean hash = true; + for (int i = 0; i < obj.length; ++i) + hash ^= obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.c new file mode 100644 index 00000000000..5347f7e8c19 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_ByteArrayCriticalLocker + * Method: criticalNative + */ +JNIEXPORT jbyte JNICALL Java_nsk_share_gc_lock_jni_ByteArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jbyteArray arr; + jbyte *pa; + jbyte hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return 0; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.java new file mode 100644 index 00000000000..f7a28713a44 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class ByteArrayCriticalLocker extends CriticalSectionObjectLocker { + private native byte criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("ByteArrayCriticalLocker"); + } + + public ByteArrayCriticalLocker(byte[] obj) { + super(obj); + } + protected void criticalSection(long enterTime, long sleepTime) { + byte javaHash = hashValue(obj); + byte nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + + private byte hashValue(byte[] obj) { + byte hash = 0; + for (int i = 0; i < obj.length; ++i) + hash ^= obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.c new file mode 100644 index 00000000000..91ad693e6ee --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_CharArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jchar JNICALL Java_nsk_share_gc_lock_jni_CharArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jcharArray arr; + jchar *pa; + jchar hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + current_time = 0; + enterTime /= 1000; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.java new file mode 100644 index 00000000000..4fd98b86955 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class CharArrayCriticalLocker extends CriticalSectionObjectLocker { + private native char criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("CharArrayCriticalLocker"); + } + + public CharArrayCriticalLocker(char[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + char javaHash = hashValue(obj); + char nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private char hashValue(char[] obj) { + char hash = 0; + for (int i = 0; i < obj.length; ++i) + hash ^= obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.c new file mode 100644 index 00000000000..2e70012f2b2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_DoubleArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jdouble JNICALL Java_nsk_share_gc_lock_jni_DoubleArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jdoubleArray arr; + jdouble *pa; + jdouble hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash += pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.java new file mode 100644 index 00000000000..c3ab24527a5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class DoubleArrayCriticalLocker extends CriticalSectionObjectLocker { + private native double criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("DoubleArrayCriticalLocker"); + } + + public DoubleArrayCriticalLocker(double[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + double javaHash = hashValue(obj); + double nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private double hashValue(double[] obj) { + double hash = 0; + for (int i = 0; i < obj.length; ++i) + hash += obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.c new file mode 100644 index 00000000000..c5720c46381 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_FloatArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jfloat JNICALL Java_nsk_share_gc_lock_jni_FloatArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jfloatArray arr; + jfloat *pa; + jfloat hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash += pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.java new file mode 100644 index 00000000000..5009136dc4b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class FloatArrayCriticalLocker extends CriticalSectionObjectLocker { + private native float criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("FloatArrayCriticalLocker"); + } + + public FloatArrayCriticalLocker(float[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + float javaHash = hashValue(obj); + float nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private float hashValue(float[] obj) { + float hash = 0; + for (int i = 0; i < obj.length; ++i) + hash += obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.c new file mode 100644 index 00000000000..cd0074f14a3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_IntArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jint JNICALL Java_nsk_share_gc_lock_jni_IntArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jintArray arr; + jint *pa; + jint hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.java new file mode 100644 index 00000000000..bbd3d799fc6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class IntArrayCriticalLocker extends CriticalSectionObjectLocker { + private native int criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("IntArrayCriticalLocker"); + } + + public IntArrayCriticalLocker(int[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + int javaHash = hashValue(obj); + int nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private int hashValue(int[] obj) { + int hash = 0; + for (int i = 0; i < obj.length; ++i) + hash ^= obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/JNILockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/JNILockers.java new file mode 100644 index 00000000000..1ebca961afc --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/JNILockers.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class JNILockers implements Lockers { + public Locker createLocker(Object obj) { + if (obj instanceof String) + return new StringCriticalLocker((String) obj); + if (obj instanceof boolean[]) + return new BooleanArrayCriticalLocker((boolean[]) obj); + if (obj instanceof byte[]) + return new ByteArrayCriticalLocker((byte[]) obj); + if (obj instanceof char[]) + return new CharArrayCriticalLocker((char[]) obj); + if (obj instanceof double[]) + return new DoubleArrayCriticalLocker((double[]) obj); + if (obj instanceof float[]) + return new FloatArrayCriticalLocker((float[]) obj); + if (obj instanceof int[]) + return new IntArrayCriticalLocker((int[]) obj); + if (obj instanceof long[]) + return new LongArrayCriticalLocker((long[]) obj); + if (obj instanceof short[]) + return new ShortArrayCriticalLocker((short[]) obj); + throw new TestBug("Cannot create locker for: " + obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.c new file mode 100644 index 00000000000..6a58cd47ee6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_LongArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jlong JNICALL Java_nsk_share_gc_lock_jni_LongArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jlongArray arr; + jlong *pa; + jlong hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.java new file mode 100644 index 00000000000..bcb55e45758 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class LongArrayCriticalLocker extends CriticalSectionObjectLocker { + private native long criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("LongArrayCriticalLocker"); + } + + public LongArrayCriticalLocker(long[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + long javaHash = hashValue(obj); + long nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private long hashValue(long[] obj) { + long hash = 0; + for (int i = 0; i < obj.length; ++i) + hash ^= obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.c new file mode 100644 index 00000000000..e69173323bb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_ShortArrayCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jshort JNICALL Java_nsk_share_gc_lock_jni_ShortArrayCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jshortArray arr; + jshort *pa; + jshort hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return 0; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return 0; + } + } + arr = (*env)->GetObjectField(env, this, objFieldId); + if (arr == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetArrayLength(env, arr); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = 0; + } + mssleep((long) sleepTime); + (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, arr); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.java new file mode 100644 index 00000000000..774d6b7cb28 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +public class ShortArrayCriticalLocker extends CriticalSectionObjectLocker { + private native short criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("ShortArrayCriticalLocker"); + } + + public ShortArrayCriticalLocker(short[] obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + short javaHash = hashValue(obj); + short nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) + throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + } + + private short hashValue(short[] obj) { + short hash = 0; + for (int i = 0; i < obj.length; ++i) + hash ^= obj[i]; + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.c new file mode 100644 index 00000000000..4eb6b8bbd3e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jni_StringCriticalLocker + * Method: criticalNative + * Signature: ([Z)Z + */ +JNIEXPORT jchar JNICALL Java_nsk_share_gc_lock_jni_StringCriticalLocker_criticalNative +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jsize size, i; + jstring str; + const jchar *pa; + jchar hash = 0; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return JNI_FALSE; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return JNI_FALSE; + } + } + str = (*env)->GetObjectField(env, this, objFieldId); + if (str == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return JNI_FALSE; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + size = (*env)->GetStringLength(env, str); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + pa = (*env)->GetStringCritical(env, str, NULL); + if (pa != NULL) { + for (i = 0; i < size; ++i) + hash ^= pa[i]; + } else { + hash = JNI_FALSE; + } + mssleep((long) sleepTime); + (*env)->ReleaseStringCritical(env, str, pa); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, str); + return hash; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.java new file mode 100644 index 00000000000..478fb86414c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jni; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.gc.gp.string.RandomStringProducer; +import nsk.share.TestFailure; + +public class StringCriticalLocker extends CriticalSectionObjectLocker { + private native char criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("StringCriticalLocker"); + } + + public StringCriticalLocker(String obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { +// System.out.println("Lock: " + s); + char javaHash = hashValue(obj); + char nativeHash = criticalNative(enterTime, sleepTime); + if (nativeHash != 0 && nativeHash != javaHash) +// throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash); + throw new TestFailure("Native hash differs from java hash"); + } + + private char hashValue(String s) { + char hash = 0; + for (int i = 0; i < s.length(); ++i) + hash ^= s.charAt(i); + return hash; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.c new file mode 100644 index 00000000000..deebad377f1 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jniref_JNIGlobalRefLocker + * Method: criticalNative + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIGlobalRefLocker_criticalNative + (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jobject obj; + jobject gref; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return; + } + } + obj = (*env)->GetObjectField(env, this, objFieldId); + if (obj == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + gref = (*env)->NewGlobalRef(env, obj); + mssleep((long) sleepTime); + (*env)->DeleteGlobalRef(env, gref); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.java new file mode 100644 index 00000000000..d1b706559c2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +/** + * Locker that uses JNI function NewGlobalRef. + */ +public class JNIGlobalRefLocker extends CriticalSectionObjectLocker { + private native void criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("JNIGlobalRefLocker"); + } + + public JNIGlobalRefLocker(Object obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + criticalNative(enterTime, sleepTime); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLockers.java new file mode 100644 index 00000000000..e18ccfcb25c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLockers.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class JNIGlobalRefLockers implements Lockers { + public Locker createLocker(Object obj) { + return new JNIGlobalRefLocker(obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.c new file mode 100644 index 00000000000..bb8a478b76e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jniref_JNILocalRefLocker + * Method: criticalNative + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNILocalRefLocker_criticalNative + (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jobject obj; + jobject gref; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return; + } + } + obj = (*env)->GetObjectField(env, this, objFieldId); + if (obj == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + gref = (*env)->NewLocalRef(env, obj); + mssleep((long) sleepTime); + (*env)->DeleteLocalRef(env, gref); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.java new file mode 100644 index 00000000000..4e17e1d7ea6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +/** + * Locker that uses JNI function NewLocalRef. + */ +public class JNILocalRefLocker extends CriticalSectionObjectLocker { + private native void criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("JNILocalRefLocker"); + } + + public JNILocalRefLocker(Object obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + criticalNative(enterTime, sleepTime); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLockers.java new file mode 100644 index 00000000000..d4041127cd6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLockers.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class JNILocalRefLockers implements Lockers { + public Locker createLocker(Object obj) { + return new JNILocalRefLocker(obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.c new file mode 100644 index 00000000000..55e6eddfb47 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jniref_JNIRefLocker + * Method: criticalNative + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIRefLocker_criticalNative + (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jobject obj; + jobject gref, lref, gwref; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return; + } + } + obj = (*env)->GetObjectField(env, this, objFieldId); + if (obj == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + gref = (*env)->NewGlobalRef(env, obj); + lref = (*env)->NewLocalRef(env, obj); + gwref = (*env)->NewWeakGlobalRef(env, obj); + mssleep((long) sleepTime); + (*env)->DeleteGlobalRef(env, gref); + (*env)->DeleteLocalRef(env, lref); + (*env)->DeleteWeakGlobalRef(env, gwref); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.java new file mode 100644 index 00000000000..67b91b29abd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +/** + * JNIRefLocker locks objects using JNI functions + * NewGlobalRef, NewLocalRef, NewWeakGlobalRef + */ +public class JNIRefLocker extends CriticalSectionObjectLocker { + private native void criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("JNIRefLocker"); + } + + public JNIRefLocker(Object obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + criticalNative(enterTime, sleepTime); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLockers.java new file mode 100644 index 00000000000..0e37811cb01 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLockers.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class JNIRefLockers implements Lockers { + public Locker createLocker(Object obj) { + return new JNIRefLocker(obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.c new file mode 100644 index 00000000000..9670aa4e3e2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +static jfieldID objFieldId = NULL; + +/* + * Class: nsk_share_gc_lock_jniref_JNIWeakGlobalRefLocker + * Method: criticalNative + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIWeakGlobalRefLocker_criticalNative + (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + jobject obj; + jobject gref; + time_t start_time, current_time; + + if (objFieldId == NULL) { + jclass class = (*env)->GetObjectClass(env, this); + if (class == NULL) { + printf("Error: GetObjectClass returned NULL\n"); + return; + } + objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;"); + if (objFieldId == NULL) { + printf("Error: GetFieldID returned NULL\n"); + return; + } + } + obj = (*env)->GetObjectField(env, this, objFieldId); + if (obj == NULL) { + printf("Error: GetObjectField returned NULL\n"); + return; + } + (*env)->SetObjectField(env, this, objFieldId, NULL); + start_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - start_time < enterTime) { + gref = (*env)->NewWeakGlobalRef(env, obj); + mssleep((long) sleepTime); + (*env)->DeleteWeakGlobalRef(env, gref); + mssleep((long) sleepTime); + current_time = time(NULL); + } + (*env)->SetObjectField(env, this, objFieldId, obj); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.java new file mode 100644 index 00000000000..0a5986346f8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.gc.lock.CriticalSectionObjectLocker; +import nsk.share.TestFailure; + +/** + * Locker that uses JNI function NewWeakGlobalRef. + */ +public class JNIWeakGlobalRefLocker extends CriticalSectionObjectLocker { + private native void criticalNative(long enterTime, long sleepTime); + + static { + System.loadLibrary("JNIWeakGlobalRefLocker"); + } + + public JNIWeakGlobalRefLocker(Object obj) { + super(obj); + } + + protected void criticalSection(long enterTime, long sleepTime) { + criticalNative(enterTime, sleepTime); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLockers.java new file mode 100644 index 00000000000..a1e9feb3bf9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLockers.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jniref; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class JNIWeakGlobalRefLockers implements Lockers { + public Locker createLocker(Object obj) { + return new JNIWeakGlobalRefLocker(obj); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.c new file mode 100644 index 00000000000..5cd139f1e88 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include +#include "jni_tools.h" + +static jvmtiEnv *jvmti = NULL; +static jvmtiCapabilities caps; + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jint res; + + res = (*jvm)->GetEnv(jvm, (void **) &jvmti, JVMTI_VERSION_1_0); + if (res != JNI_OK || jvmti == NULL) { + printf("Wrong result of a valid call to GetEnv!\n"); + return JNI_ERR; + } + return JNI_OK; +} + +/* + * Class: nsk_share_gc_lock_jvmti_JVMTIAllocLocker + * Method: jVMTIAllocSection + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jvmti_JVMTIAllocLocker_jVMTIAllocSection +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + unsigned char *ptr; + time_t current_time, old_time; + jvmtiError err; + old_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - old_time < enterTime) { + err = (*jvmti)->Allocate(jvmti, 1, &ptr); + mssleep((long) sleepTime); + err = (*jvmti)->Deallocate(jvmti, ptr); + mssleep((long) sleepTime); + current_time = time(NULL); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.java new file mode 100644 index 00000000000..5af9496941b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jvmti; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Locker; +import nsk.share.gc.lock.CriticalSectionTimedLocker; + +/** + * Malloc locker tries to hold malloc lock (if there is any) + * by calling malloc() and free() in a loop. + */ +public class JVMTIAllocLocker extends CriticalSectionTimedLocker { + static { + System.loadLibrary("JVMTIAllocLocker"); + } + + public JVMTIAllocLocker() { + } + + public JVMTIAllocLocker(long enterTime, long sleepTime) { + super(enterTime, sleepTime); + setSleepTime(sleepTime); + } + + /** + * This native method does Allocate() / Deallocate() in a loop + * while java field locked is set to true, sleeping + * for sleepTime between Allocate() and Deallocate() and after + * Deallocate(). + */ + private native void jVMTIAllocSection(long enterTime, long sleepTime); + + protected void criticalSection(long enterTime, long sleepTime) { + jVMTIAllocSection(enterTime, sleepTime); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLockers.java new file mode 100644 index 00000000000..386b17f859b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLockers.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.jvmti; + +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class JVMTIAllocLockers implements Lockers { + public Locker createLocker(Object obj) { + return new JVMTIAllocLocker(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.c new file mode 100644 index 00000000000..9afe41af645 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include +#include +#include +#include "jni_tools.h" + +/* + * Class: nsk_share_gc_lock_malloc_MallocLocker + * Method: mallocSection + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_nsk_share_gc_lock_malloc_MallocLocker_mallocSection +(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) { + char *ptr; + time_t current_time, old_time; + old_time = time(NULL); + enterTime /= 1000; + current_time = 0; + while (current_time - old_time < enterTime) { + ptr = malloc(1); + mssleep((long) sleepTime); + free(ptr); + mssleep((long) sleepTime); + current_time = time(NULL); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.java new file mode 100644 index 00000000000..12426c42a8b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.malloc; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Locker; +import nsk.share.gc.lock.CriticalSectionTimedLocker; + +/** + * Malloc locker tries to hold malloc lock (if there is any) + * by calling malloc() and free() in a loop. + */ +public class MallocLocker extends CriticalSectionTimedLocker { + static { + System.loadLibrary("MallocLocker"); + } + + public MallocLocker() { + } + + public MallocLocker(long enterTime, long sleepTime) { + super(enterTime, sleepTime); + } + + /** + * This native method does malloc() / free() in a loop + * while java field locked is set to true, sleeping + * for sleepTime between malloc() and free() and after + * free(). + */ + private native void mallocSection(long enterTime, long sleepTime); + + protected void criticalSection(long enterTime, long sleepTime) { + mallocSection(enterTime, sleepTime); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLockers.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLockers.java new file mode 100644 index 00000000000..91874d540b8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLockers.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.lock.malloc; + +import nsk.share.TestBug; +import nsk.share.gc.lock.Lockers; +import nsk.share.gc.lock.Locker; + +public class MallocLockers implements Lockers { + public Locker createLocker(Object obj) { + return new MallocLocker(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/Tree.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/Tree.java new file mode 100644 index 00000000000..13e0832e127 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/Tree.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.tree; + +public class Tree { + private final long nodeSize; + private TreeNode root; + + public Tree(long nodeSize) { + this.nodeSize = nodeSize; + root = new TreeNode(nodeSize); + } + + public Tree(TreeNode root) { + this.nodeSize = root.getSize(); + setRoot(root); + } + + public TreeNode follow(int path, int depth) { + return root.follow(path, depth); + } + + public int getHeight() { + return root.getHeight(); + } + + public TreeNode newNode() { + return new TreeNode(nodeSize); + } + + public final TreeNode getRoot() { + return root; + } + + public final void setRoot(TreeNode root) { + this.root = root; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/TreeNode.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/TreeNode.java new file mode 100644 index 00000000000..9f67e5cb980 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/TreeNode.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.gc.tree; + +import nsk.share.gc.Memory; +import nsk.share.gc.gp.GarbageProducer; + +/** + * A node of binary tree. + * + * A height of subtree defined by this node is kept in the node. + * Additionaly, a byte array is used to control how much memory + * this node will occupy. + */ +public final class TreeNode { + private TreeNode left, right; + // The height of the tree + private int height; + private int size; + private Object storage; + + + /** + * Create a tree node that will occupy approximately given memory. + * + * @param memory memory + */ + public TreeNode(long memory) { + int length = (int) (memory - (4 * 2 + 2 * Memory.getReferenceSize() + Memory.getObjectExtraSize())); + if (length > 0) + storage = new byte[length]; + size = length; + } + + /** + * Create a tree node that will occupy approximately given memory. + * + * @param memory memory + */ + public TreeNode(long size, GarbageProducer gp) { + int length = (int) (size - (4 * 2 + 2 * Memory.getReferenceSize() + Memory.getObjectExtraSize())); + if (length > 0) + storage = gp.create(length); + size = length; + } + /** + * Create a tree node that will occupy approximately given memory + * with given left and right children. + * + * @param memory memory + * @param left left child + * @param right right child + */ + public TreeNode(long memory, TreeNode left, TreeNode right) { + this(memory); + setLeft(left); + setRight(right); + setHeight(1 + Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight())); + } + + /** + * Create a tree node that will occupy approximately given memory + * with given left and right children. + * + * @param memory memory + * @param left left child + * @param right right child + */ + public TreeNode(long memory, GarbageProducer gp, TreeNode left, TreeNode right) { + this(memory, gp); + setLeft(left); + setRight(right); + setHeight(1 + Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight())); + } + + /** + * Get memory that this node occupies. + * + * @return memory size + */ + public long getSize() { + int length = storage == null ? 0 : size; + return length + 4 * 2 + 2 * Memory.getReferenceSize() + Memory.getObjectExtraSize(); + } + + /** + * Get memory that this subtree occupies. + * + * @return memory size + */ + public long getTotalSize() { + long memory = getSize(); + if (left != null) + memory += left.getSize(); + if (right != null) + memory += right.getSize(); + return memory; + } + + /** + * Follow path determined by bits given integer and depth. + * + * @param path path encoded in integer + * @param depth depth to follow + * @return end of the path + */ + public TreeNode follow(int path, int depth) { + if (depth == 0) + return this; + TreeNode current = this; + TreeNode prev = null; + for (int i = 0; i < depth; ++i) { + prev = current; + if ((path & 1) == 0) + current = current.left; + else + current = current.right; + path >>= 1; + } + return prev; + } + + /** + * Swap left child of this node with left child of another node. + * + * @param another another node + */ + public void swapLeft(TreeNode another) { + TreeNode tmp = another.left; + another.left = left; + left = tmp; + } + /** + * Swap right child of this node with right child of another node. + * + * @param another another node + */ + public void swapRight(TreeNode another) { + TreeNode tmp = another.right; + another.right = right; + right = tmp; + } + + public final TreeNode getLeft() { + return left; + } + + public final void setLeft(TreeNode left) { + this.left = left; + } + + public final TreeNode getRight() { + return right; + } + + public final void setRight(TreeNode right) { + this.right = right; + } + + public final int getHeight() { + return height; + } + + public boolean hasLeft() { + return left != null; + } + + public boolean hasRight() { + return right != null; + } + + /** + * Get actual height of the tree. + */ + public int getActualHeight() { + return 1 + Math.max(left == null ? 0 : left.getActualHeight(), right == null ? 0 : right.getActualHeight()); + } + + /** + * Get lenght of shortest path from root to leaf in the tree. + */ + public int getShortestPath() { + return 1 + Math.min(left == null ? 0 : left.getActualHeight(), right == null ? 0 : right.getActualHeight()); + } + + public final void setHeight(int value) { + this.height = value; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/AbstractJDIDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/AbstractJDIDebuggee.java new file mode 100644 index 00000000000..d2f3eecbb16 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/AbstractJDIDebuggee.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import nsk.share.jpda.*; + +public class AbstractJDIDebuggee extends AbstractDebuggeeTest { + + /* + * Create argument handler handling options specific for JDI tests + */ + protected DebugeeArgumentHandler createArgumentHandler(String args[]) { + return new ArgumentHandler(args); + } + + public static void main(String args[]) { + AbstractJDIDebuggee debuggee = new AbstractJDIDebuggee(); + debuggee.init(args); + debuggee.doTest(); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java new file mode 100644 index 00000000000..fee4baf773e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java @@ -0,0 +1,653 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import nsk.share.*; +import nsk.share.jpda.*; + +import com.sun.jdi.VirtualMachine; + +/** + * Parser for JDI test's specific command-line arguments. + *

      + * ArgumentHandler handles JDI test's specific + * arguments related to launching debugee VM using JDI features + * in addition to general arguments recognized by + * DebugeeArgumentHandler and ArgumentParser. + *

      + * Following is the list of specific options recognized by + * AgrumentHandler: + *

        + *
      • -connector=[launching|attaching|listening|default] - + * JDI connector type + *
      • -transport=[socket|shmem|default] - + * JDWP transport kind + *
      • -jdi.trace=[none|all|events|sends|receives|reftypes|objrefs] - + * JDI trace mode for debugee VM + *
      + *

      + * See also list of arguments recognized by the base DebugeeArgumentHandler + * and ArgumentParser classes. + *

      + * See also description of ArgumentParser how to work with + * command line arguments and options. + * + * @see ArgumentParser + * @see DebugeeArgumentHandler + */ +public class ArgumentHandler extends DebugeeArgumentHandler { + + static private String JDI_CONNECTOR_NAME_PREFIX = "com.sun.jdi."; + + /** + * Keep a copy of raw command-line arguments and parse them; + * but throw an exception on parsing error. + * + * @param args Array of the raw command-line arguments. + * + * @throws NullPointerException If args==null. + * @throws IllegalArgumentException If Binder or Log options + * are set incorrectly. + * + * @see #setRawArguments(String[]) + */ + public ArgumentHandler(String args[]) { + super(args); +// parseArguments(); + } + + /** + * Overriden method returns transport type for JDWP connection, specified by + * -transport command line option, or "default" value + * by default. + * + * @see #getTransportName() + * @see #isSocketTransport() + * @see #isShmemTransport() + * @see #isDefaultTransport() + * @see #setRawArguments(String[]) + */ + public String getTransportType() { + return options.getProperty("transport", "default"); + } + + /** + * Overriden method returns true if socket transport + * is used either as specified or as a platform default transport. + * + * @see #getTransportType() + */ + public boolean isSocketTransport() { + String transport = getTransportType(); + if (transport.equals("socket")) + return true; + if (transport.equals("shmem")) + return false; + if (transport.equals("default")) { + String arch = getArch(); + if (arch == null) + if (System.getProperty("os.arch").equals("windows-i586")) + return false; + else + return true; + else if (arch.equals("windows-i586")) + return false; + else + return true; + } + throw new TestBug("Bad value of argument transport: " + transport); + } + + /** + * Overriden method returns true if shmem transport is used + * either as specified or as a platform default transport. + * + * @see #getTransportType() + */ + public boolean isShmemTransport() { + return ! isSocketTransport(); + } + + /** + * Overriden method returns true if transport type is default. + * + * @see #getTransportType() + */ + public boolean isDefaultTransport() { + String transport = getTransportType(); + return transport.equals("default"); + } + + /** + * Overriden methos returns JDI connector type, specified by + * -connector. or "default" value by default. + * + * @see #getConnectorName() + * @see #isLaunchingConnector() + * @see #isAttachingConnector() + * @see #isListeningConnector() + * @see #isDefaultConnector() + * @see #setRawArguments(String[]) + */ + public String getConnectorType() { + return options.getProperty("connector", "default"); + } + + /** + * Overriden method returns full connector name corresponding to + * the used connector and transport types. + * + * @see #getConnectorType() + * @see #getTransportType() + */ + public String getConnectorName() { + if (isLaunchingConnector()) { + if (isRawLaunchingConnector()) + return JDI_CONNECTOR_NAME_PREFIX + "RawCommandLineLaunch"; + return JDI_CONNECTOR_NAME_PREFIX + "CommandLineLaunch"; + } + if (isAttachingConnector()) { + if (isSocketTransport()) + return JDI_CONNECTOR_NAME_PREFIX + "SocketAttach"; + if (isShmemTransport()) + return JDI_CONNECTOR_NAME_PREFIX + "SharedMemoryAttach"; + return JDI_CONNECTOR_NAME_PREFIX + "SocketAttach"; + } + if (isListeningConnector()) { + if (isSocketTransport()) + return JDI_CONNECTOR_NAME_PREFIX + "SocketListen"; + if (isShmemTransport()) + return JDI_CONNECTOR_NAME_PREFIX + "SharedMemoryListen"; + return JDI_CONNECTOR_NAME_PREFIX + "SocketListen"; + } + throw new Failure("Unable to find full name of connector \"" + getConnectorType() + + "\" for transport \"" + getTransportType() + "\""); + } + + /** + * Overriden method returns true if connector type is default. + * + * @see #getConnectorType() + */ + public boolean isDefaultConnector() { + return getConnectorType().equals("default"); + } + + /** + * Return true if connector type is launching + * rawlaunching or default. + * + * @see #getConnectorType() + */ + public boolean isLaunchingConnector() { + return getConnectorType().equals("launching") + || getConnectorType().equals("rawlaunching") + || getConnectorType().equals("default"); + } + + /** + * Return true if connector type is rawlaunching. + * + * @see #getConnectorType() + */ + public boolean isRawLaunchingConnector() { + return getConnectorType().equals("rawlaunching"); + } + + /** + * Return string representation of debug trace mode, specified by + * -jdi.trace command line option, or "none" + * value by default. + *

      + * Possible values for this option are the same as symbolic constants names + * in com.sun.jdi.VirtualMachine interface: + *
        "all", or + *
        "events", or + *
        "none", or + *
        "objrefs", or + *
        "receives", or + *
        "reftypes", or + *
        "sends". + * + * @see #getTraceMode() + * @see #setRawArguments(String[]) + */ + public String getTraceModeString() { + return options.getProperty("jdi.trace", "none"); + } + + /** + * Return integer code corresponding to debug trace mode, specified by + * -jdi.trace command line option, or VirtualMachine.TRACE_NONE + * value by default. + *

      + * Possible values are the same as symbolic constant values + * in com.sun.jdi.VirtualMachine interface: + *

        + *
      • VirtualMachine.TRACE_ALL + *
      • VirtualMachine.TRACE_EVENTS + *
      • VirtualMachine.TRACE_NONE + *
      • VirtualMachine.TRACE_OBJREFS + *
      • VirtualMachine.TRACE_RECEIVES + *
      • VirtualMachine.TRACE_REFTYPES + *
      • VirtualMachine.TRACE_SENDS + *
      + * + * @see #getTraceModeString() + * @see #setRawArguments(String[]) + */ + public int getTraceMode() { + String val = getTraceModeString(); + if (val == null) + return VirtualMachine.TRACE_NONE; + if (val.equals("none")) + return VirtualMachine.TRACE_NONE; + if (val.equals("all")) + return VirtualMachine.TRACE_ALL; + if (val.equals("events")) + return VirtualMachine.TRACE_EVENTS; + if (val.equals("objrefs")) + return VirtualMachine.TRACE_OBJREFS; + if (val.equals("receives")) + return VirtualMachine.TRACE_RECEIVES; + if (val.equals("reftypes")) + return VirtualMachine.TRACE_REFTYPES; + if (val.equals("sends")) + return VirtualMachine.TRACE_SENDS; + throw new TestBug("Unknown JDI trace mode string: " + val); + } + + // delay between connection attempts, used in connectors tests + public int getConnectionDelay() { + String value = options.getProperty("connectionDelay", "4000"); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not integer value of \"connectionDelay\" argument: " + value); + } + } + + + /** + * Return true if the test should pass in any case i.e. + * an entity specified by the arguments entry[] is + * not implemented on the tested platform. Name of the tested + * platform is resolved from the "-arch" option. + * + * @param entry Array with the arguments which are specifing + * the entity. + * + * @throws Oddity If test parameter-arch + * has not been set. + * + * @see #setRawArguments(String[]) + */ + public boolean shouldPass(String entry[]) { + String arch; + boolean found = false; + + if ((arch=getArch()) == null) + throw new Oddity("Test parameter -arch should be set"); + + for (int i=0; i < CheckedFeatures.notImplemented.length; i++) { + if (CheckedFeatures.notImplemented[i][0].equals(arch) && + CheckedFeatures.notImplemented[i].length == (entry.length+1)) { + for (int j=1; j < (entry.length+1); j++) { + if (CheckedFeatures.notImplemented[i][j].equals(entry[j-1])) + found = true; + else { + found = false; + break; + } + } + if (found) return true; // the entry[] is not implemented + } + } + + return false; // the entry[] is implemented + } + + /** + * Return true if the test should pass in any case i.e. + * an entity specified by the argument entry is + * not implemented on the tested platform. Name of the tested + * platform is resolved from the "-arch" option. + * + * @param entry String with the argument which is specifing + * the entity. + * + * @throws Oddity If test parameter-arch + * has not been set. + * + * @see #setRawArguments(String[]) + */ + public boolean shouldPass(String entry) { + return (shouldPass(new String[] {entry})); + } + + /** + * Return true if the test should pass in any case i.e. + * an entity specified by the arguments entry1 and + * entry2 is not implemented on the tested platform. + * The entry is considered to be not implemented if exact entry + * "entry1, entry2" or its main entry "entry1" is not implemented. + * + * Name of the tested platform is resolved from the "-arch" + * option. + * + * @param entry1 String with the argument 1 which is specifing + * the entity. + * + * @param entry2 String with the argument 2 which is specifing + * the entity. + * + * @throws Oddity If test parameter-arch + * has not been set. + * + * @see #setRawArguments(String[]) + */ + public boolean shouldPass(String entry1, String entry2) { + return ( shouldPass(new String[] {entry1, entry2}) || + shouldPass(new String[] {entry1}) ); + } + + /** + * Check if an option is admissible and has proper value. + * This method is invoked by parseArguments() + * + * @param option option name + * @param value string representation of value (could be an empty string) + * null if this option has no value + * @return true if option is admissible and has proper value + * false if otion is not admissible + * + * @throws BadOption if option has illegal value + * + * @see #parseArguments() + */ + protected boolean checkOption(String option, String value) { + + // check options with enumerated values + + if (option.equals("connectionDelay")) { + try { + int number = Integer.parseInt(value); + if (number <= 0) { + throw new BadOption(option + ": must be a positive integer"); + } + } catch (NumberFormatException e) { + throw new BadOption(option + ": must be an integer"); + } + + return true; + } + + if (option.equals("connector")) { + if ((!value.equals("launching")) + && (!value.equals("rawlaunching")) + && (!value.equals("attaching")) + && (!value.equals("listening")) + && (!value.equals("default"))) { + throw new BadOption(option + ": value must be one of: " + + "launching, attaching, listening, default"); + } + return true; + } + + if (option.equals("transport")) { + if ((!value.equals("socket")) + && (!value.equals("shmem")) + && (!value.equals("default"))) { + throw new BadOption(option + ": must be one of: " + + "socket, shmem, default"); + } + return true; + } + + if (option.equals("jdi.trace")) { + if ((!value.equals("all")) + && (!value.equals("none")) + && (!value.equals("events")) + && (!value.equals("receives")) + && (!value.equals("sends")) + && (!value.equals("reftypes")) + && (!value.equals("objrefs"))) { + throw new BadOption(option + ": value must be one of: " + + "none, all, events, receives, sends, reftypes, objrefs"); + } + return true; + } + + return super.checkOption(option, value); + } + + /** + * Check options against inconcistence. + * This method is invoked by parseArguments() + * + * @see #parseArguments() + */ + protected void checkOptions() { +/* + if (isTransportAddressDynamic() && + (!isDefaultConnector() && isRawLaunchingConnector())) { + throw new BadOption("-transport.address=dynamic should NOT be used with" + + " -connector=rawlaunching"); + } + */ + + if (! isLaunchedLocally() && ! isDefaultDebugeeSuspendMode()) { + throw new BadOption("inconsistent options: " + + "-debugee.launch=" + getLaunchMode() + + " and -debugee.suspend=" + getDebugeeSuspendMode()); + } + + if (! isLaunchedLocally() && isLaunchingConnector()) { + throw new BadOption("inconsistent options: " + + "-debugee.launch=" + getLaunchMode() + + " and -connector=" + getConnectorType()); + } + + if (isLaunchingConnector() && ! isDefaultTransport()) { + throw new BadOption("inconsistent options: " + + "-connector=" + getConnectorType() + + " and -transport=" + getTransportType()); + } + + if (! isLaunchingConnector() && isDefaultTransport()) { + throw new BadOption("inconsistent options: " + + "-connector=" + getConnectorType() + + " and -transport=" + getTransportType()); + } + + if (! isDefaultJVMDIStrictMode()) { + throw new BadOption("unsupported options: " + + "jvmdi.strict: non default JVMDI strict mode is not supported now" + getJVMDIStrictMode()); + } + +/* + if (! isLaunchedLocally() && ! isDefaultJVMDIStrictMode()) { + throw new BadOption("inconsistent options: " + + "-launch.mode=" + getLaunchMode() + + " and -jvmdi.strict=" + getJVMDIStrictMode()); + } + */ + + super.checkOptions(); + } +} + +/** + * This is an auxiliary class intended for ArgumentHandler. + * The following information is used by the ArgumentHandler + * for resolving features (i.e., JDI connectors and transport names) + * which are not implemented on given platform (the first column). + * This list is actual for JDK 1.3.x, 1.4.x, 1.5.0, 1.6.0. + * + * @see ArgumentHandler + */ +class CheckedFeatures { + + static final String[][] notImplemented = { + + // attaching connectors + /* + * From docs/technotes/guides/jpda/conninv.html: + * " + * This connector can be used by a debugger application to attach to + * a currently running target VM through the shared memory transport. It is + * available only on the Microsoft Windows platform. + * " + */ + {"solaris-sparc", "com.sun.jdi.SharedMemoryAttach"}, + {"solaris-sparcv9", "com.sun.jdi.SharedMemoryAttach"}, + {"solaris-i586", "com.sun.jdi.SharedMemoryAttach"}, + {"solaris-amd64", "com.sun.jdi.SharedMemoryAttach"}, + {"solaris-x64", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-i586", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-ia64", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-amd64", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-x64", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-sparc", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-sparcv9", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-aarch64", "com.sun.jdi.SharedMemoryAttach"}, + {"linux-arm", "com.sun.jdi.SharedMemoryAttach"}, + {"macosx-amd64", "com.sun.jdi.SharedMemoryAttach"}, + {"mac-x64", "com.sun.jdi.SharedMemoryAttach"}, + + // listening connectors + /* + * From docs/technotes/guides/jpda/conninv.html: + * " + * This connector can be used by a debugger application to accept a + * connection from a separately invoked target VM through the shared memory + * transport. + * It is available only on the Microsoft Windows platform. + * " + */ + {"solaris-sparc", "com.sun.jdi.SharedMemoryListen"}, + {"solaris-sparcv9", "com.sun.jdi.SharedMemoryListen"}, + {"solaris-i586", "com.sun.jdi.SharedMemoryListen"}, + {"solaris-amd64", "com.sun.jdi.SharedMemoryListen"}, + {"solaris-x64", "com.sun.jdi.SharedMemoryListen"}, + {"linux-i586", "com.sun.jdi.SharedMemoryListen"}, + {"linux-ia64", "com.sun.jdi.SharedMemoryListen"}, + {"linux-amd64", "com.sun.jdi.SharedMemoryListen"}, + {"linux-x64", "com.sun.jdi.SharedMemoryListen"}, + {"linux-sparc", "com.sun.jdi.SharedMemoryListen"}, + {"linux-sparcv9", "com.sun.jdi.SharedMemoryListen"}, + {"linux-aarch64", "com.sun.jdi.SharedMemoryListen"}, + {"linux-arm", "com.sun.jdi.SharedMemoryListen"}, + {"macosx-amd64", "com.sun.jdi.SharedMemoryListen"}, + {"mac-x64", "com.sun.jdi.SharedMemoryListen"}, + + // launching connectors + /* + * From docs/technotes/guides/jpda/conninv.html: + * " + * Sun Command Line Launching Connector + * This connector can be used by a debugger application to launch a + * Sun VM or any other VM which supports the same invocation options with + * respect to debugging. The details of launching the VM and specifying the + * necessary debug options are handled by the connector. The underlying + * transport used by this connector depends on the platform. On Microsoft + * Windows, the shared memory transport is used. On Solaris and Linux the + * socket transport is used. + * " + */ + {"solaris-sparc", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"solaris-sparc", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"solaris-sparcv9", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"solaris-sparcv9", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"solaris-i586", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"solaris-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"solaris-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"solaris-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"solaris-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"solaris-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-i586", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-ia64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-ia64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-sparc", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-sparc", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-sparcv9", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-sparcv9", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-aarch64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-aarch64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"linux-arm", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"linux-arm", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"windows-i586", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, + {"windows-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, + + {"windows-ia64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, + {"windows-ia64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, + + {"windows-amd64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, + {"windows-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, + + {"windows-x64", "com.sun.jdi.CommandLineLaunch", "dt_socket"}, + {"windows-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"}, + + {"macosx-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"macosx-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + {"mac-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"}, + {"mac-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"}, + + // shared memory transport is implemented only on windows platform + {"solaris-sparc", "dt_shmem"}, + {"solaris-sparcv9", "dt_shmem"}, + {"solaris-i586", "dt_shmem"}, + {"solaris-amd64", "dt_shmem"}, + {"solaris-x64", "dt_shmem"}, + {"linux-i586", "dt_shmem"}, + {"linux-ia64", "dt_shmem"}, + {"linux-amd64", "dt_shmem"}, + {"linux-x64", "dt_shmem"}, + {"linux-sparc", "dt_shmem"}, + {"linux-sparcv9", "dt_shmem"}, + {"linux-aarch64", "dt_shmem"}, + {"linux-arm", "dt_shmem"}, + {"macosx-amd64", "dt_shmem"}, + {"mac-x64", "dt_shmem"}, + }; +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Binder.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Binder.java new file mode 100644 index 00000000000..1d5f9b2faa5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Binder.java @@ -0,0 +1,1273 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import nsk.share.*; +import nsk.share.jpda.*; + +import com.sun.jdi.*; +import com.sun.jdi.connect.*; + +import com.sun.jdi.connect.Connector.Argument; +import java.io.*; +import java.net.*; +import java.util.*; + +/** + * This class provides debugger with connection to debugee VM + * using JDI connectors. + *

      + * This class provides abilities to launch and bind to debugee VM + * as described for base DebugeeBinder class, + * using JDI connectors and com.sun.VirtualMachine mirror. + *

      + * When Binder is asked to bind to debugee by invoking + * bindToBebugee() method it uses + * com.sun.jdi.Connector object corresponding to + * value of command line options -connector and + * -transport to launch and connect to debugee VM. + * After debugee is launched and connection is established + * Binder uses com.sun.jdi.VirtualMachine + * object to construct Debugee object, that + * provides abilities to interact with debugee VM. + * + * @see Debugee + * @see DebugeeBinder + */ +public class Binder extends DebugeeBinder { + + /** + * Default message prefix for Binder object. + */ + public static final String LOG_PREFIX = "binder> "; + + /** + * Get version string. + */ + public static String getVersion () { + return "@(#)Binder.java 1.14 03/10/08"; + } + + // -------------------------------------------------- // + + /** + * Handler of command line arguments. + */ + private ArgumentHandler argumentHandler = null; + + /** + * Return argumentHandler of this binder. + */ + public ArgumentHandler getArgumentHandler() { + return argumentHandler; + } + + // -------------------------------------------------- // + + /** + * Make Binder object and pass raw command line arguments. + * + * @deprecated Use newer + * Binder(ArgumentHandler,Log) + * constructor. + */ + public Binder (String args[]) { + this(args, new Log(System.err)); + } + + /** + * Make Binder object for raw command line arguments + * and specified log object. + * + * @deprecated Use newer + * Binder(ArgumentHandler,Log) + * constructor. + */ + public Binder (String args[], Log log) { + this(new ArgumentHandler(args), log); + } + + /** + * Make Binder object for specified command line arguments + * and log object. + */ + public Binder (ArgumentHandler argumentHandler, Log log) { + super(argumentHandler, log); + this.argumentHandler = argumentHandler; + } + + // -------------------------------------------------- // + + /** + * Make initial Debugee object for local debuggee process + * started with launching connector. + */ + public Debugee makeLocalDebugee(Process process) { + LocalLaunchedDebugee debugee = new LocalLaunchedDebugee(process, this); + + Finalizer finalizer = new Finalizer(debugee); + finalizer.activate(); + + return debugee; + } + + /** + * Launch local debuggee process with specified command line + * and make initial Debugee object. + */ + public Debugee startLocalDebugee(String cmd) { + Process process = null; + + try { + process = launchProcess(cmd); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while launching local debuggee VM process:\n\t" + + e); + } + + return makeLocalDebugee(process); + } + + /** + * Make debuggee wrapper for already launched debuggee VM. + * After enwraping debugee's output is redirected to Binder's log, + * VMStartEvent is received and debuggee is initialized. + */ + public Debugee enwrapDebugee(VirtualMachine vm, Process proc) { + Debugee debugee = makeLocalDebugee(proc); + + display("Redirecting VM output"); + debugee.redirectOutput(log); + debugee.setupVM(vm); + + long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds + + display("Waiting for VM initialized"); + debugee.waitForVMInit(timeout); + + return debugee; + } + + /** + * Launch debugee VM and establish connection to it without waiting for VMStartEvent. + * After launching debugee's output is redirected to Binder's log, + * but VMStartEvent is not received and so debuggee is not fully initialized. + * + * @see #bindToDebugee(String) + */ + public Debugee bindToDebugeeNoWait(String classToExecute) { + + VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); + display("VirtualMachineManager: version " + + vmm.majorInterfaceVersion() + "." + + vmm.minorInterfaceVersion()); + + Debugee debugee = null; + + String classPath = null; +// classPath = System.getProperty("java.class.path"); + + prepareForPipeConnection(argumentHandler); + + if (argumentHandler.isLaunchedLocally()) { + + if (argumentHandler.isDefaultConnector()) { + debugee = localDefaultLaunchDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isRawLaunchingConnector()) { + debugee = localRawLaunchDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isLaunchingConnector()) { + debugee = localLaunchDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isAttachingConnector()) { + debugee = localLaunchAndAttachDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isLaunchingConnector()) { + debugee = localLaunchDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isListeningConnector()) { + debugee = localLaunchAndListenDebugee(vmm, classToExecute, classPath); + } else { + throw new TestBug("Unexpected connector type for local debugee launch mode" + + argumentHandler.getConnectorType()); + } + + } else if (argumentHandler.isLaunchedRemotely()) { + + connectToBindServer(classToExecute); + + if (argumentHandler.isAttachingConnector()) { + debugee = remoteLaunchAndAttachDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isListeningConnector()) { + debugee = remoteLaunchAndListenDebugee(vmm, classToExecute, classPath); + } else { + throw new TestBug("Unexpected connector type for remote debugee launch mode" + + argumentHandler.getConnectorType()); + } + + } else if (argumentHandler.isLaunchedManually()) { + + if (argumentHandler.isAttachingConnector()) { + debugee = manualLaunchAndAttachDebugee(vmm, classToExecute, classPath); + } else if (argumentHandler.isListeningConnector()) { + debugee = manualLaunchAndListenDebugee(vmm, classToExecute, classPath); + } else { + throw new TestBug("Unexpected connector type for manual debugee launch mode" + + argumentHandler.getConnectorType()); + } + + } else { + throw new Failure("Unexpected debugee launching mode: " + argumentHandler.getLaunchMode()); + } + + return debugee; + } + + /** + * Launch debugee VM and establish JDI connection. + * After launching debugee's output is redirected to Binder's log, + * VMStart event is received and debuggee is initialized. + * + * @see #bindToDebugeeNoWait(String) + */ + public Debugee bindToDebugee(String classToExecute) { + Debugee debugee = bindToDebugeeNoWait(classToExecute); + + if(argumentHandler.getOptions().getProperty("traceAll") != null) + debugee.VM().setDebugTraceMode(VirtualMachine.TRACE_ALL); + + long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds + + display("Waiting for VM initialized"); + debugee.waitForVMInit(timeout); + + return debugee; + } + + // -------------------------------------------------- // + + /** + * Launch debugee locally via the default LaunchingConnector. + */ + private Debugee localDefaultLaunchDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + "default" ); + LaunchingConnector connector = vmm.defaultConnector(); + Map arguments = setupLaunchingConnector(connector, classToExecute, classPath); + + VirtualMachine vm; + try { + display("Launching debugee"); + vm = connector.launch(arguments); + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e); + } catch (VMStartException e) { + e.printStackTrace(log.getOutStream()); + String msg = readVMStartExceptionOutput(e, log.getOutStream()); + throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\n" + msg); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while launching debugee VM:\n\t" + e); + }; + + Process process = vm.process(); + Debugee debugee = makeLocalDebugee(process); + debugee.redirectOutput(log); + debugee.setupVM(vm); + + return debugee; + } + + + /** + * Launch debugee locally via the default LaunchingConnector. + */ + private Debugee localLaunchDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + + display("Finding connector: " + argumentHandler.getConnectorName() ); + LaunchingConnector connector = + (LaunchingConnector) findConnector(argumentHandler.getConnectorName(), + vmm.launchingConnectors()); + Map arguments = setupLaunchingConnector(connector, classToExecute, classPath); + + VirtualMachine vm; + try { + display("Launching debugee"); + vm = connector.launch(arguments); + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e); + } catch (VMStartException e) { + e.printStackTrace(log.getOutStream()); + String msg = readVMStartExceptionOutput(e, log.getOutStream()); + throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while launching debugee VM:\n\t" + e); + }; + + Process process = vm.process(); + Debugee debugee = makeLocalDebugee(process); + debugee.redirectOutput(log); + debugee.setupVM(vm); + + return debugee; + } + + /** + * Launch debugee locally via the RawLaunchingConnector. + */ + private Debugee localRawLaunchDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + argumentHandler.getConnectorName() ); + LaunchingConnector connector = + (LaunchingConnector) findConnector(argumentHandler.getConnectorName(), + vmm.launchingConnectors()); + Map arguments = setupRawLaunchingConnector(connector, classToExecute, classPath); + + VirtualMachine vm; + try { + display("Launching debugee"); + vm = connector.launch(arguments); + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e); + } catch (VMStartException e) { + e.printStackTrace(log.getOutStream()); + String msg = readVMStartExceptionOutput(e, log.getOutStream()); + throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while launching debugee VM:\n\t" + e); + }; + + Process process = vm.process(); + Debugee debugee = makeLocalDebugee(process); + debugee.redirectOutput(log); + debugee.setupVM(vm); + + return debugee; + } + + /** + * Launch debugee VM locally as a local process and connect to it using + * AttachingConnector. + */ + private Debugee localLaunchAndAttachDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("FindingConnector: " + argumentHandler.getConnectorName() ); + AttachingConnector connector = + (AttachingConnector) findConnector(argumentHandler.getConnectorName(), + vmm.attachingConnectors()); + Map arguments = setupAttachingConnector(connector, classToExecute, classPath); + + String address = makeTransportAddress(); + String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address); + String javaCmdLine = makeCommandLineString(classToExecute, address, "\""); + + display("Starting java process:\n\t" + javaCmdLine); + Debugee debugee = startLocalDebugee(cmdLineArgs); + debugee.redirectOutput(log); + + display("Attaching to debugee"); + VirtualMachine vm = null; + IOException ioe = null; + for (int i = 0; i < CONNECT_TRIES; i++) { + try { + vm = connector.attach(arguments); + display("Debugee attached"); + debugee.setupVM(vm); + return debugee; + } catch (IOException e) { + display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e); + ioe = e; + if (debugee.terminated()) { + throw new Failure("Unable to connect to debuggee VM: VM process is terminated"); + } + try { + Thread.currentThread().sleep(CONNECT_TRY_DELAY); + } catch (InterruptedException ie) { + ie.printStackTrace(log.getOutStream()); + throw new Failure("Thread interrupted while pausing connection attempts:\n\t" + + ie); + } + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e); + } + } + throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES + + " tries:\n\t" + ioe); + } + + /** + * Launch debugee VM locally as a local process and connect to it using + * ListeningConnector. + */ + private Debugee localLaunchAndListenDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + argumentHandler.getConnectorName() ); + ListeningConnector connector = + (ListeningConnector) findConnector(argumentHandler.getConnectorName(), + vmm.listeningConnectors()); + Map arguments = setupListeningConnector(connector, classToExecute, classPath); + + String address = null; + try { + display("Listening for connection from debugee"); + address = connector.startListening(arguments); + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e); + }; + + String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address); + String javaCmdLine = makeCommandLineString(classToExecute, address, "\""); + + display("Starting java process:\n\t" + javaCmdLine); + Debugee debugee = startLocalDebugee(cmdLineArgs); + debugee.redirectOutput(log); + + display("Waiting for connection from debugee"); + VirtualMachine vm = null; + IOException ioe = null; + for (int i = 0; i < CONNECT_TRIES; i++) { + try { + vm = connector.accept(arguments); + connector.stopListening(arguments); + display("Debugee attached"); + debugee.setupVM(vm); + return debugee; + } catch (IOException e) { + display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e); + ioe = e; + if (debugee.terminated()) { + throw new Failure("Unable to connect to debuggee VM: VM process is terminated"); + } + try { + Thread.currentThread().sleep(CONNECT_TRY_DELAY); + } catch (InterruptedException ie) { + ie.printStackTrace(log.getOutStream()); + throw new Failure("Thread interrupted while pausing connection attempts:\n\t" + + ie); + } + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e); + } + } + throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES + + " tries:\n\t" + ioe); + } + + // -------------------------------------------------- // + + /** + * Launch debugee VM remotely via BindServer and connect to it using + * AttachingConnector. + */ + private Debugee remoteLaunchAndAttachDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + argumentHandler.getConnectorName() ); + AttachingConnector connector = + (AttachingConnector) findConnector(argumentHandler.getConnectorName(), + vmm.attachingConnectors()); + + Map arguments = setupAttachingConnector(connector, classToExecute, classPath); + + String address = makeTransportAddress(); + String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address); + String javaCmdLine = makeCommandLineString(classToExecute, address, "\""); + + display("Starting remote java process:\n\t" + javaCmdLine); + Debugee debugee = startRemoteDebugee(cmdLineArgs); + + display("Attaching to debugee"); + VirtualMachine vm; + IOException ioe = null; + for (int i = 0; i < CONNECT_TRIES; i++) { + try { + vm = connector.attach(arguments); + display("Debugee attached"); + debugee.setupVM(vm); + return debugee; + } catch (IOException e) { + display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e); + ioe = e; + if (debugee.terminated()) { + throw new Failure("Unable to connect to debuggee VM: VM process is terminated"); + } + try { + Thread.currentThread().sleep(CONNECT_TRY_DELAY); + } catch (InterruptedException ie) { + ie.printStackTrace(log.getOutStream()); + throw new Failure("Thread interrupted while pausing connection attempts:\n\t" + + ie); + } + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e); + } + } + throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES + + " tries:\n\t" + ioe); + } + + /** + * Launch debugee VM remotely via BindServer and connect to it using + * ListeningConnector. + */ + private Debugee remoteLaunchAndListenDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + argumentHandler.getConnectorName() ); + ListeningConnector connector = + (ListeningConnector) findConnector(argumentHandler.getConnectorName(), + vmm.listeningConnectors()); + Map arguments = setupListeningConnector(connector, classToExecute, classPath); + + String address = null; + try { + display("Listening for connection from debugee"); + address = connector.startListening(arguments); + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e); + }; + + String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address); + String javaCmdLine = makeCommandLineString(classToExecute, address, "\""); + + display("Starting remote java process:\n\t" + javaCmdLine); + Debugee debugee = startRemoteDebugee(cmdLineArgs); + + display("Waiting for connection from debugee"); + VirtualMachine vm; + IOException ioe = null; + for (int i = 0; i < CONNECT_TRIES; i++) { + try { + vm = connector.accept(arguments); + connector.stopListening(arguments); + display("Debugee attached"); + debugee.setupVM(vm); + return debugee; + } catch (IOException e) { + display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e); + ioe = e; + if (debugee.terminated()) { + throw new Failure("Unable to connect to debuggee VM: VM process is terminated"); + } + try { + Thread.currentThread().sleep(CONNECT_TRY_DELAY); + } catch (InterruptedException ie) { + ie.printStackTrace(log.getOutStream()); + throw new Failure("Thread interrupted while pausing connection attempts:\n\t" + + ie); + } + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e); + } + } + throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES + + " tries:\n\t" + ioe); + } + + // -------------------------------------------------- // + + /** + * Prompt to manually launch debugee VM and connect to it using + * AttachingConnector. + */ + private Debugee manualLaunchAndAttachDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + argumentHandler.getConnectorName() ); + AttachingConnector connector = + (AttachingConnector) findConnector(argumentHandler.getConnectorName(), + vmm.attachingConnectors()); + Map arguments = setupAttachingConnector(connector, classToExecute, classPath); + + String address = makeTransportAddress(); + String javaCmdLine = makeCommandLineString(classToExecute, address, "\""); + + display("Starting manual java process:\n\t" + javaCmdLine); + ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine); + + VirtualMachine vm; + try { + display("Attaching to debugee"); + vm = connector.attach(arguments); + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while attaching to debugee VM:\n\t" + e); + }; + display("Debugee attached"); + + debugee.setupVM(vm); + return debugee; + } + + /** + * Prompt to manually launch debugee VM and connect to it using + * ListeningConnector. + */ + private Debugee manualLaunchAndListenDebugee (VirtualMachineManager vmm, + String classToExecute, + String classPath) { + display("Finding connector: " + argumentHandler.getConnectorName() ); + ListeningConnector connector = + (ListeningConnector) findConnector(argumentHandler.getConnectorName(), + vmm.listeningConnectors()); + Map arguments = setupListeningConnector(connector, classToExecute, classPath); + + VirtualMachine vm; + try { + display("Listening for connection from debugee"); + String address = connector.startListening(arguments); + String javaCmdLine = makeCommandLineString(classToExecute, address, "\""); + display("Starting manual java process:\n\t" + javaCmdLine); + ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine); + display("Waiting for connection from debugee"); + vm = connector.accept(arguments); + display("Debugee attached"); + connector.stopListening(arguments); + debugee.setupVM(vm); + return debugee; + } catch (IllegalConnectorArgumentsException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while listening to debugee VM:\n\t" + e); + } + } + + // -------------------------------------------------- // + + /** + * Make proper arguments for LaunchingConnector. + */ + private Map setupLaunchingConnector(LaunchingConnector connector, + String classToExecute, + String classPath) { + display("LaunchingConnector:"); + display(" name: " + connector.name()); + display(" description: " + connector.description()); + display(" transport: " + connector.transport()); + + Hashtable arguments = new Hashtable(connector.defaultArguments()); + + Connector.Argument arg; + + arg = (Connector.StringArgument) arguments.get("quote"); + String quote = arg.value(); + + String cmdline = classToExecute + " " + + ArgumentHandler.joinArguments(argumentHandler.getRawArguments(), quote); + + arg = (Connector.StringArgument) arguments.get("main"); + arg.setValue(cmdline); + + if (! argumentHandler.willDebugeeSuspended()) { + Connector.BooleanArgument barg = (Connector.BooleanArgument) arguments.get("suspend"); + barg.setValue(true); + } + +/* + if (! argumentHandler.isJVMDIStrictMode()) { + arg = (Connector.StringArgument) arguments.get("options"); + arg.setValue("strict=y"); + } + */ + + if (! argumentHandler.isDefaultDebugeeJavaHome()) { + arg = (Connector.StringArgument) arguments.get("home"); + arg.setValue(argumentHandler.getDebugeeJavaHome()); + } + + if (! argumentHandler.isDefaultLaunchExecName()) { + arg = (Connector.StringArgument) arguments.get("vmexec"); + arg.setValue(argumentHandler.getLaunchExecName()); + } + + String vmArgs = ""; + + String vmUserArgs = argumentHandler.getLaunchOptions(); + + if (vmUserArgs != null) { + vmArgs = vmUserArgs; + } + +/* + if (classPath != null) { + vmArgs += " -classpath " + quote + classPath + quote; + } + */ + + if (vmArgs.length() > 0) { + arg = (Connector.StringArgument) arguments.get("options"); + arg.setValue(vmArgs); + } + + display("Connector arguments:"); + Iterator iterator = arguments.values().iterator(); + while (iterator.hasNext()) { + display(" " + iterator.next()); + } + return arguments; + } + + /** + * Make proper arguments for RawLaunchingConnector. + */ + private Map setupRawLaunchingConnector(LaunchingConnector connector, + String classToExecute, + String classPath) { + display("RawLaunchingConnector:"); + display(" name: " + connector.name()); + display(" description: " + connector.description()); + display(" transport: " + connector.transport()); + + Hashtable arguments = new Hashtable(connector.defaultArguments()); + + String connectorAddress; + String vmAddress; + + if (argumentHandler.isSocketTransport()) { + connectorAddress = argumentHandler.getTransportPort(); + vmAddress = argumentHandler.getDebugeeHost() + + ":" + argumentHandler.getTransportPort(); + } else if (argumentHandler.isShmemTransport() ) { + connectorAddress = argumentHandler.getTransportSharedName(); + vmAddress=connectorAddress; + } else { + throw new TestBug("Undefined transport type for AttachingConnector"); + } + + Connector.Argument arg; + + arg = (Connector.StringArgument) arguments.get("quote"); + String quote = arg.value(); + + String javaCmdLine = makeCommandLineString(classToExecute, quote); + + arg = (Connector.StringArgument) arguments.get("command"); + arg.setValue(javaCmdLine); + + arg = (Connector.StringArgument) arguments.get("address"); + arg.setValue(connectorAddress); + + display("Connector arguments:"); + Iterator iterator = arguments.values().iterator(); + while (iterator.hasNext()) { + display(" " + iterator.next()); + } + return arguments; + } + + /** + * Make proper arguments for AttachingConnector. + */ + private Map setupAttachingConnector(AttachingConnector connector, + String classToExecute, + String classPath) { + display("AttachingConnector:"); + display(" name: " + connector.name()); + display(" description: " + connector.description()); + display(" transport: " + connector.transport()); + + Hashtable arguments = new Hashtable(connector.defaultArguments()); + + Connector.Argument arg; + if (argumentHandler.isSocketTransport()) { + arg = (Connector.StringArgument) arguments.get("hostname"); + arg.setValue(argumentHandler.getDebugeeHost()); + Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port"); + iarg.setValue(argumentHandler.getTransportPortNumber()); + } else { + arg = (Connector.StringArgument) arguments.get("name"); + arg.setValue(argumentHandler.getTransportSharedName()); + } + + display("Connector arguments:"); + Iterator iterator = arguments.values().iterator(); + while (iterator.hasNext()) { + display(" " + iterator.next()); + } + return arguments; + } + + /** + * Make proper arguments for ListeningConnector. + */ + private Map setupListeningConnector(ListeningConnector connector, + String classToExecute, + String classPath) { + display("ListeningConnector:"); + display(" name: " + connector.name()); + display(" description: " + connector.description()); + display(" transport: " + connector.transport()); + + Hashtable arguments = new Hashtable(connector.defaultArguments()); + + Connector.Argument arg; + if (argumentHandler.isSocketTransport()) { + if (!argumentHandler.isTransportAddressDynamic()) { + int port = argumentHandler.getTransportPortNumber(); + Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port"); + iarg.setValue(port); + } + } else { + String sharedName = argumentHandler.getTransportSharedName(); + arg = (Connector.StringArgument) arguments.get("name"); + arg.setValue(sharedName); + } + + display("Connector arguments:"); + Iterator iterator = arguments.values().iterator(); + while (iterator.hasNext()) { + display(" " + iterator.next()); + } + return arguments; + } + + // -------------------------------------------------- // + + /** + * Find connector by name from given connectors list. + */ + private Connector findConnector(String connectorName, List connectors) { + Iterator iter = connectors.iterator(); + + while (iter.hasNext()) { + Connector connector = (Connector) iter.next(); + if (connector.name().equals(connectorName)) { + return connector; + } + } + throw new Failure("JDI connector not found: " + connectorName); + } + + // -------------------------------------------------- // + + /** + * Launch local debuggee process with specified command line arguments + * and make initial Debugee mirror. + */ + protected Debugee startLocalDebugee(String[] cmdArgs) { + Process process = null; + + try { + process = launchProcess(cmdArgs); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while launching local debuggee VM process:\n\t" + + e); + } + + return makeLocalDebugee(process); + } + + /** + * Launch remote debuggee process with specified command line arguments + * and make initial Debugee mirror. + */ + protected RemoteLaunchedDebugee startRemoteDebugee(String[] cmdArgs) { + try { + launchRemoteProcess(cmdArgs); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while launching remote debuggee VM process:\n\t" + + e); + } + + RemoteLaunchedDebugee debugee = new RemoteLaunchedDebugee(this); + + Finalizer finalizer = new Finalizer(debugee); + finalizer.activate(); + + return debugee; + } + + /** + * Launch manual debuggee process with specified command line arguments + * and make initial Debugee mirror. + */ + protected ManualLaunchedDebugee startManualDebugee(String cmd) { + ManualLaunchedDebugee debugee = new ManualLaunchedDebugee(this); + debugee.launchDebugee(cmd); + + Finalizer finalizer = new Finalizer(debugee); + finalizer.activate(); + + return debugee; + } + + public static String readVMStartExceptionOutput(VMStartException e, PrintStream log) { + StringBuffer msg = new StringBuffer(); + try (InputStream is = e.process().getInputStream()) { + msg.append("\tstdout: ").append(new String(readAllBytes(is))).append('\n'); + } catch (IOException e1) { + log.println("Could not read normal output from launched process:" + e1); + } + try (InputStream is = e.process().getErrorStream()) { + msg.append("\tstderr: ").append(new String(readAllBytes(is))); + } catch (IOException e1) { + log.println("Could not read error output from launched process:" + e1); + } + return msg.toString(); + } + + /** + * Copied from the JDK 9 implementation in InputStream.java + */ + private static byte[] readAllBytes(InputStream is) throws IOException { + final int DEFAULT_BUFFER_SIZE = 8192; + final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + + byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; + int capacity = buf.length; + int nread = 0; + int n; + for (;;) { + // read to EOF which may read more or less than initial buffer size + while ((n = is.read(buf, nread, capacity - nread)) > 0) + nread += n; + + // if the last call to read returned -1, then we're done + if (n < 0) + break; + + // need to allocate a larger buffer + if (capacity <= MAX_BUFFER_SIZE - capacity) { + capacity = capacity << 1; + } else { + if (capacity == MAX_BUFFER_SIZE) + throw new OutOfMemoryError("Required array size too large"); + capacity = MAX_BUFFER_SIZE; + } + buf = Arrays.copyOf(buf, capacity); + } + return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); + } + +} + + +/** + * Mirror of locally launched debugee. + */ +final class LocalLaunchedDebugee extends Debugee { + + /** Enwrap the locally started VM process. */ + public LocalLaunchedDebugee (Process process, Binder binder) { + super(binder); + this.process = process; + checkTermination = true; + } + + // ---------------------------------------------- // + + /** Return exit status of the debugee VM. */ + public int getStatus () { + return process.exitValue(); + } + + /** Check whether the debugee VM has been terminated. */ + public boolean terminated () { + if (process == null) + return true; + + try { + int value = process.exitValue(); + return true; + } catch (IllegalThreadStateException e) { + return false; + } + } + + // ---------------------------------------------- // + + /** Kill the debugee VM. */ + protected void killDebugee () { + super.killDebugee(); + if (!terminated()) { + log.display("Killing debugee VM process"); + process.destroy(); + } + } + + /** Wait until the debugee VM shutdown or crash. */ + protected int waitForDebugee () throws InterruptedException { + int code = process.waitFor(); + return code; + } + + /** Get a pipe to write to the debugee's stdin stream. */ + protected OutputStream getInPipe () { + return process.getOutputStream(); + } + + /** Get a pipe to read the debugee's stdout stream. */ + protected InputStream getOutPipe () { + return process.getInputStream(); + } + + /** Get a pipe to read the debugee's stderr stream. */ + protected InputStream getErrPipe () { + return process.getErrorStream(); + } +} + + +/** + * Mirror of remotely launched debugee. + */ +final class RemoteLaunchedDebugee extends Debugee { + + /** Enwrap the remotely started VM process. */ + public RemoteLaunchedDebugee (Binder binder) { + super(binder); + } + + // ---------------------------------------------- // + + /** Return exit status of the debugee VM. */ + public int getStatus () { + return binder.getRemoteProcessStatus(); + } + + /** Check whether the debugee VM has been terminated. */ + public boolean terminated () { + return binder.isRemoteProcessTerminated(); + } + + // ---------------------------------------------- // + + /** Kill the debugee VM. */ + protected void killDebugee () { + super.killDebugee(); + if (!terminated()) { + binder.killRemoteProcess(); + } + } + + /** Wait until the debugee VM shutdown or crash. */ + protected int waitForDebugee () { + return binder.waitForRemoteProcess(); + } + + /** Get a pipe to write to the debugee's stdin stream. */ + protected OutputStream getInPipe () { + return null; + } + + /** Get a pipe to read the debugee's stdout stream. */ + protected InputStream getOutPipe () { + return null; + } + + /** Get a pipe to read the debugee's stderr stream. */ + protected InputStream getErrPipe () { + return null; + } + + public void redirectStdout(OutputStream out) { + } + + public void redirectStdout(Log log, String prefix) { + } + + public void redirectStderr(OutputStream out) { + } + + public void redirectStderr(Log log, String prefix) { + } +} + + +/** + * Mirror of manually launched debugee. + */ +final class ManualLaunchedDebugee extends Debugee { + /** Enwrap the manually started VM process. */ + public ManualLaunchedDebugee (Binder binder) { + super(binder); + makeInputReader(); + } + + // ---------------------------------------------- // + + private int exitCode = 0; + private boolean finished = false; + private static BufferedReader bin = null; + + public void launchDebugee(String commandLine) { + makeInputReader(); + + putMessage("Launch target VM using such command line:\n" + + commandLine); + String answer = askQuestion("Has the VM successfully started? (yes/no)", "yes"); + for ( ; ; ) { + if (answer.equals("yes")) + break; + if (answer.equals("no")) + throw new Failure ("Unable to manually launch debugee VM"); + answer = askQuestion("Wrong answer. Please type yes or no", "yes"); + } + } + + private static void makeInputReader() { + if (bin == null) { + bin = new BufferedReader(new InputStreamReader(System.in)); + } + } + + private static void destroyInputReader() { + if (bin != null) { + try { + bin.close(); + } catch (IOException e) { +// e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while closing input stream:\n\t" + e); + } + bin = null; + } + } + + private static void putMessage(String msg) { + System.out.println("\n>>> " + msg); + } + + private static String askQuestion(String question, String defaultAnswer) { + try { + System.out.print("\n>>> " + question); + System.out.print(" [" + defaultAnswer + "] "); + System.out.flush(); + String answer = bin.readLine(); + if (answer.equals("")) + return defaultAnswer; + return answer; + } catch (IOException e) { +// e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while reading answer:\n\t" + e); + } + } + + /** Return exit status of the debugee VM. */ + public int getStatus () { + if (! finished) { + throw new Failure("Unable to get status of debugee VM: process still alive"); + } + return exitCode; + } + + /** Check whether the debugee VM has been terminated. */ + public boolean terminated () { + return finished; + } + + // ---------------------------------------------- // + + /** Kill the debugee VM. */ + protected void killDebugee () { + super.killDebugee(); + if (!terminated()) { + putMessage("Kill launched VM"); + String answer = askQuestion("Has the VM successfully terminated? (yes/no)", "yes"); + for ( ; ; ) { + if (answer.equals("yes")) { + finished = true; + break; + } + if (answer.equals("no")) + throw new Failure ("Unable to manually kill debugee VM"); + answer = askQuestion("Wrong answer. Please type yes or no", "yes"); + } + } + } + + /** Wait until the debugee VM shutdown or crash. */ + protected int waitForDebugee () { + putMessage("Wait for launched VM to exit."); + String answer = askQuestion("What is VM exit code?", "95"); + for ( ; ; ) { + try { + exitCode = Integer.parseInt(answer); + break; + } catch (NumberFormatException e) { + answer = askQuestion("Wrong answer. Please type integer value", "95"); + } + } + finished = true; + return exitCode; + } + + /** Get a pipe to write to the debugee's stdin stream. */ + protected OutputStream getInPipe () { + return null; + } + + /** Get a pipe to read the debugee's stdout stream. */ + protected InputStream getOutPipe () { + return null; + } + + /** Get a pipe to read the debugee's stderr stream. */ + protected InputStream getErrPipe () { + return null; + } + + public void redirectStdout(OutputStream out) { + } + + public void redirectStdout(Log log, String prefix) { + } + + public void redirectStderr(OutputStream out) { + } + + public void redirectStderr(Log log, String prefix) { + } + + public void close() { + destroyInputReader(); + super.close(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ConnectorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ConnectorTest.java new file mode 100644 index 00000000000..931b166aa28 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ConnectorTest.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import com.sun.jdi.connect.*; +import com.sun.jdi.*; +import java.io.*; +import java.util.*; + +import nsk.share.*; +import nsk.share.jpda.*; + +/* + * This class contains several common methods used by connector tests. + */ +public abstract class ConnectorTest { + protected Log log; + + protected VirtualMachine vm; + + protected int attempts; // attempts to connect to the debuggee VM + + protected int delay; // delay between connection attempts + + protected IORedirector outRedirector; + + protected IORedirector errRedirector; + + protected ArgHandler argHandler; + + protected boolean isTestFailed; + + // set test status 'FAILED' + protected void testFailed() { + isTestFailed = true; + } + + // check if tested functionality implemented on current platform + protected boolean shouldPass() { + return argHandler.shouldPass(getConnectorName()); + } + + abstract protected void doTest(); + + abstract protected String getConnectorName(); + + abstract protected String getDebuggeeClass(); + + static public class ArgHandler extends ArgumentHandler { + public ArgHandler(String[] args) { + super(args); + + } + + protected boolean checkOption(String option, String value) { + if (super.checkOption(option, value)) + return true; + + if (option.equals("testWorkDir")) + return true; + + if (option.equals("waitVMStartEvent")) + return true; + + return false; + } + + public String getTestWorkDir() { + String dir = options.getProperty("testWorkDir"); + + if (dir.endsWith(File.separator)) { + dir = dir.substring(0, dir.length() - 1); + } + + return dir; + } + + public boolean waitVMStartEvent() { + return options.containsKey("waitVMStartEvent"); + } + } + + /* + * Subclasses can provide another ArgumentHandlers + */ + protected ArgHandler createArgumentHandler(String[] args) { + return new ArgHandler(args); + } + + protected void init(String[] args, PrintStream out) { + argHandler = createArgumentHandler(args); + + log = new Log(out, argHandler); + + delay = argHandler.getConnectionDelay(); + + // calculate number of connection attempts to not exceed WAITTIME + long timeout = argHandler.getWaitTime() * 60 * 1000; + attempts = (int) (timeout / delay); + } + + protected int runIt(String argv[], PrintStream out) { + try { + init(argv, out); + + if (shouldPass()) { + log.display("Tested functionality isn't implemented on this platform. Treat test as passed."); + return Consts.TEST_PASSED; + } + + doTest(); + + if (isTestFailed) + return Consts.TEST_FAILED; + else + return Consts.TEST_PASSED; + + } catch (Throwable t) { + out.println("Unexpected exception: " + t); + t.printStackTrace(out); + return Consts.TEST_FAILED; + } + } + + protected void waitForVMInit(VirtualMachine vm) { + Debugee.waitForVMInit(vm, log, argHandler.getWaitTime() * 60 * 1000); + } + + // set connector argument value with given name + protected void setConnectorArg(Map args, String argName, String value) { + for (String key : args.keySet()) { + Connector.Argument arg = args.get(key); + if (arg.name().equals(argName)) { + arg.setValue(value); + return; + } + } + + throw new Error("There is no argument '" + argName + "'"); + } + + // try attach to target VM using attaching connector + protected VirtualMachine tryAttach(AttachingConnector connector, Map cArgs) { + // make several attempts to connect to the debuggee VM until WAITTIME exceeds + for (int i = 0; i < attempts; i++) { + try { + return connector.attach(cArgs); + } catch (IOException e) { + // could not connect; sleep a few and make new attempt + log.display("Connection attempt #" + i + " failed: " + e); + e.printStackTrace(log.getOutStream()); + try { + Thread.sleep(delay); + } catch (InterruptedException ie) { + testFailed(); + log.complain("TEST INCOMPLETE: interrupted sleep: " + ie); + ie.printStackTrace(log.getOutStream()); + } + } catch (IllegalConnectorArgumentsException e) { + testFailed(); + log.complain("TEST: Illegal connector arguments: " + e.getMessage()); + return null; + } catch (Exception e) { + testFailed(); + log.complain("TEST: Internal error: " + e.getMessage()); + e.printStackTrace(log.getOutStream()); + return null; + } + } + + testFailed(); + // return null after all attempts failed + log.complain("FAILURE: all attempts to connect to the debuggee VM failed"); + return null; + } + + // try find connector with given name + protected Connector findConnector(String connectorName) { + List connectors = Bootstrap.virtualMachineManager().allConnectors(); + Iterator iter = connectors.iterator(); + + while (iter.hasNext()) { + Connector connector = (Connector) iter.next(); + if (connector.name().equals(connectorName)) { + log.display("Connector name=" + connector.name() + "\n\tdescription=" + connector.description() + "\n\ttransport=" + + connector.transport().name()); + return connector; + } + } + throw new Error("No appropriate connector"); + } + + // wait when debuggee process finishes and check exit code + protected void waitDebuggeeExit(Debugee debuggee) { + log.display("\nwaiting for debuggee VM exit"); + int code = debuggee.waitFor(); + if (code != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) { + testFailed(); + log.complain("Debuggee VM has crashed: exit code=" + code); + return; + } + log.display("debuggee VM: exit code=" + code); + } + + // wait 'READY' command from debuggee VM (this method is used by debuggers establishing socket connection with debuggee VM) + protected boolean waitReadyCommand(IOPipe pipe) { + String command = pipe.readln(); + log.display("Command: " + command); + + if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) { + testFailed(); + log.complain("Unexpected debuggee answer: " + command + ", expected is " + AbstractDebuggeeTest.COMMAND_READY); + return false; + } + + return true; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java new file mode 100644 index 00000000000..dd11ccc4025 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import nsk.share.*; +import nsk.share.jpda.*; + +import com.sun.jdi.*; +import com.sun.jdi.request.*; +import com.sun.jdi.event.*; + +import java.util.*; + +/** + * This class is used to interact with debugee VM using JDI features. + *

      + * This class is wrapper for debugee VM constructed by Binder + * and it uses com.sun.jdi.VirtualMachine to interact with debugee VM. + *

      + * In addition to the general abities to control of debugee VM process, + * provided by the base class DebugeeProcess, this class + * adds also several service methods over the JDI features to simplify interaction + * with debugee VM (such as finding classes, setting breakpoints, + * handling events, and so on.). + * + * @see Binder + * @see DebugeeProcess + */ +abstract public class Debugee extends DebugeeProcess { + /** + * Mirror of the debugee VM. This must be initialized by every + * particular non-abstract class extending Debugee class. + */ + protected VirtualMachine vm = null; + + /** Binder that created this debugee. */ + protected Binder binder = null; + + /** Argument handler. */ + protected ArgumentHandler argumentHandler = null; + + /** Create new Debugee object for a given binder. */ + protected Debugee (Binder binder) { + super(binder); + this.binder = binder; + this.argumentHandler = (ArgumentHandler)binder.getArgumentHandler(); + } + + /** Setup Debugee object with given VM mirror. */ + public void setupVM(VirtualMachine vm) { + if (this.vm != null) { + throw new TestBug("Setting duplicated VM mirror for Debugee object"); + } + this.vm = vm; + int traceMode = argumentHandler.getTraceMode(); + if (traceMode != VirtualMachine.TRACE_NONE) { + display("Setting JDI trace mode to: " + argumentHandler.getTraceModeString()); + setDebugTraceMode(traceMode); + } + } + + /** Return Binder of the debugee object. */ + public Binder getBinder() { + return binder; + } + + /** Return JDI mirror of the debugee VM. */ + public VirtualMachine VM() { + return vm; + } + + /** Return EventRequestManager of the debugee object. */ + public EventRequestManager getEventRequestManager() { + return vm.eventRequestManager(); + } + + // --------------------------------------------------- // + + /** List of the currently running threads. */ + public ThreadReference[] threads () { + List list = vm.allThreads(); + int size = list.size(); + ThreadReference array[] = new ThreadReference[size]; + Iterator iterator = list.iterator(); + for (int i = 0; i < size; i++) + array[i] = (ThreadReference) iterator.next(); + if (iterator.hasNext()) + throw new Oddity("extra element in a list?"); + return array; + } + + /** List of all types loaded by the debugee VM. */ + public ReferenceType[] classes() { + return classes(null); + } + + /** + * List of all classes of the given name loaded by + * the debugee VM; or list of all classes, if name + * is null. + */ + private ReferenceType[] classes (String name) { + List list = (name==null)? vm.allClasses(): vm.classesByName(name); + int size = list.size(); + ReferenceType array[] = new ReferenceType [ size ]; + Iterator iterator = list.iterator(); + for (int i=0; iname + * loaded by the debugee VM; or throw TestBug exception if there + * are more than one such class found. TestFailure exception + * will be thrown in case when mirrors for classes with different + * names or duplicated mirrors were returned. + * Return null if there is no such class loaded. + */ + public ReferenceType classByName (String name) { + ReferenceType classes[] = this.classes(name); + + // if on first call debuggee doesn't return needed class try get this class one more time after delay to avoid 6446633 + if (classes == null || classes.length == 0) { + try { + Thread.sleep(1000); + } + catch(InterruptedException e) { + throw new TestBug("Unexpected InterruptedException"); + } + + classes = this.classes(name); + } + + if (classes == null || classes.length == 0) + return null; + + // analyze returned mirrors and throw appropriate exception + if (classes.length > 1) { + boolean duplicatesFound = false; + boolean differentNamesFound = false; + boolean visited[] = new boolean[classes.length]; + complain("Classes that were found for name \"" + name + "\":"); + for(ReferenceType klass : classes) { + complain("\t" + klass); + } + for(int c = 0; c < classes.length; c++) { + if(visited[c]) { + continue; + } + if(!classes[c].name().equals(name)) { + differentNamesFound = true; + continue; + } + for(int i = c + 1; i < classes.length; i++) { + if(visited[i]) { + continue; + } else { + visited[i] = true; + } + if(classes[c].classLoader() == classes[i].classLoader()) { + duplicatesFound = true; + } + } + } + if(duplicatesFound) { + throw new TestFailure("classes with the same name and " + + "loaded with the same class loader " + + "were found."); + } else if(differentNamesFound) { + throw new TestFailure("class with name different from '" + name + + "' was returned by VirutualMachine.classesByName."); + } else { + throw new TestBug("found " + classes.length + " such classes: " + name); + } + } + return classes[0]; + } + + /** + * Return mirror for the only method of the given refType + * class in the debugee VM; or throw TestBug exception if there + * are more than one such method found. Return null if + * there is no such method found. + */ + public Method methodByName(ReferenceType refType, String name) { + List methods = refType.methodsByName(name); + if (methods == null || methods.isEmpty()) return null; + if (methods.size() > 1) + throw new TestBug( + "found " + methods.size() + " such methods: " + name); + Method method = (Method)methods.get(0); + return method; + } + + /** + * Return a currently running thread of the given name; or + * throw TestBug exception if there are more than one such thread found. + * Return null if there is no such thread. + */ + public ThreadReference threadByName (String name) { + ThreadReference threads[] = this.threads(); + int count = 0, index = -1; + for (int i = 0; i < threads.length; i++) { + if (threads[i].name().compareTo(name)==0) { + count++; + index = i; + } + } + if (count == 0) + return null; + if (count > 1) + throw new TestBug( + "found " + count + " such threads: " + name); + return threads[index]; + } + + // --------------------------------------------------- // + + /** + * Returns Location object for given line number in specified method or null + * if no location for this line is found. + * + * @param method method mirror containing given line number + * @param line line number to find location + */ + public Location getLineLocation(Method method, int line) { + List locs = null; + try { + locs = method.allLineLocations(); + } catch(AbsentInformationException e) { + throw new TestBug("Unable to find location for line " + line + ": " + e); + } + Iterator iter = locs.iterator(); + while (iter.hasNext()) { + Location location = (Location)iter.next(); + if (location.lineNumber() == line) { + return location; + } + } + return null; + } + + /** + * Returns Location object for given line number in specified reference type or null + * if no location for this line is found. + * + * @param refType reference type mirror containing given line number + * @param line line number to find location + */ + public Location getLineLocation(ReferenceType refType, int line) { + List locs = null; + try { + locs = refType.allLineLocations(); + } catch(AbsentInformationException e) { + throw new TestBug("Unable to find location for line " + line + ": " + e); + } + Iterator iter = locs.iterator(); + while (iter.hasNext()) { + Location location = (Location)iter.next(); + if (location.lineNumber() == line) { + return location; + } + } + return null; + } + + // --------------------------------------------------- // + + /** + * Make disabled breakpoint to given location and return BreakpointRequest. + * + * @param location location to set breakpoint + * + * @see #setBreakpoint(Method, int) + * @see #setBreakpoint(ReferenceType, String, int) + */ + public BreakpointRequest makeBreakpoint(Location location) { + EventRequestManager evm = getEventRequestManager(); + BreakpointRequest request = evm.createBreakpointRequest(location); + display("Breakpoint set:\n\t" + request); + return request; + } + + /** + * Make disabled breakpoint to given line number in specified method + * and return BreakpointRequest. + * + * @param method method mirror to set breakpoint + * @param lineNumber line number inside the method + * + * @throws Failure if no location found for specified line number + * + * @see #makeBreakpoint(Location) + * @see #makeBreakpoint(ReferenceType, String, int) + */ + public BreakpointRequest makeBreakpoint(Method method, int lineNumber) { + Location location = getLineLocation(method, lineNumber); + if (location == null) { + throw new Failure("No location found for setting breakpoint to line " + lineNumber); + } + return makeBreakpoint(location); + } + + /** + * Make disabled breakpoint to given line number for specified method name + * of the given reference type and return BreakpointRequest. + * + * @param refType reference type for specified method + * @param methodName method name to set breakpoint + * @param lineNumber line number inside the method + * + * @throws Failure if no location found for specified line number + * + * @see #makeBreakpoint(Method, int) + */ + public BreakpointRequest makeBreakpoint(ReferenceType refType, + String methodName, int lineNumber) { + Method method = methodByName(refType, methodName); + if (method == null) { + throw new Failure("No method found for setting breakpoint: " + methodName); + } + return makeBreakpoint(method, lineNumber); + } + + /** + * Set and enable breakpoint to given line number for specified method + * and return BreakpointRequest. + * + * @param method method mirror to set breakpoint + * @param lineNumber line number inside the method + * + * @throws Failure if no location found for specified line number + * + * @see #setBreakpoint(ReferenceType, String, int) + */ + public BreakpointRequest setBreakpoint(Method method, int lineNumber) { + BreakpointRequest request = makeBreakpoint(method, lineNumber); + request.enable(); + return request; + } + + /** + * Set and enable breakpoint to given line number for specified method name + * of the given reference type and return BreakpointRequest. + * + * @param refType reference type for specified method + * @param methodName method name to set breakpoint + * @param lineNumber line number inside the method + * + * @throws Failure if no location found for specified line number + * + * @see #setBreakpoint(Method, int) + */ + public BreakpointRequest setBreakpoint(ReferenceType refType, + String methodName, int lineNumber) { + BreakpointRequest request = makeBreakpoint(refType, methodName, lineNumber); + request.enable(); + return request; + } + + // --------------------------------------------------- // + + /** Suspend the debugee VM. */ + public void suspend() { + vm.suspend(); + } + + /** Resume the debugee VM. */ + public void resume() { + vm.resume(); + } + + /** Dispose the debugee VM. */ + public void dispose() { + vm.dispose(); + } + + /* + * Set internal JDI tracing mode. + */ + public void setDebugTraceMode(int traceMode) { + vm.setDebugTraceMode(traceMode); + } + + // --------------------------------------------------- // + + /** + * Wait for the requested event and skip other events. + * + * @param request non-null value for events generated by this + * event request; null value for VMStartEvent. + * @param timeout timeout in milliseconds to wait for the requested event. + * + * @throws InterruptedException if another thread has interrupted this thread + */ + public Event waitingEvent(EventRequest request, long timeout) + throws InterruptedException { + + if (request == null) { + throw new Failure("Null request specified for waiting events: " + request); + } + + long timeToFinish = System.currentTimeMillis() + timeout; + long timeLeft = timeout; + boolean exit = false; + + display("Waiting for event by request:\n\t" + request); + + EventQueue eventQueue = vm.eventQueue(); + while (timeLeft > 0 && !exit) { + + EventSet eventSet = eventQueue.remove(timeLeft); + if (eventSet == null) { + continue; + } + + EventIterator eventIterator = eventSet.eventIterator(); + while (eventIterator.hasNext()) { + + Event event = eventIterator.nextEvent(); + EventRequest eventRequest = event.request(); + + if (request == eventRequest || request.equals(eventRequest)) { + display("Got requested event:\n\t" + event); + return event; + } else if (event instanceof VMDeathEvent) { + display("Ignore unexpected VMDeathEvent"); + } else if (event instanceof VMDisconnectEvent) { + display("Got unexpected VMDisconnectEvent"); + exit = true; + break; + } else { + display("Ignore unexpected event:\n\t" + event); + } // if + + } // while + + timeLeft = timeToFinish - System.currentTimeMillis(); + + } // while + + return null; + } + + /* + * Wait for VM to initialize by receiving initial VM_START event for specified timeout. + */ + public void waitForVMInit(long timeout) { + waitForVMInit(vm ,log, timeout); + } + + /* + * This static method is also used by nsk.share.jdi.ConnectorTest + */ + static public void waitForVMInit(VirtualMachine vm, Log log, long timeout) { + try { + EventSet eventSet = vm.eventQueue().remove(timeout); + if (eventSet == null) { + throw new Failure("No VMStartEvent received for timeout: " + timeout + " ms"); + } + EventIterator iterator = eventSet.eventIterator(); + while (iterator.hasNext()) { + Event event = iterator.nextEvent(); + if (event == null) { + throw new Failure("Null event received instead of VMStartEvent"); + } + if (event instanceof VMStartEvent) { + log.display("Initial VMStartEvent received: " + event); + } else { + throw new Failure("Unexpected event received instead of VMStartEvent: " + event); + } + } + int suspendPolicy = eventSet.suspendPolicy(); + if (suspendPolicy != EventRequest.SUSPEND_ALL) { + throw new Failure("Suspend policy of VMStartEvent is not SUSPEND_ALL: " + suspendPolicy); + } + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Thread interrupted while waiting for VMStartEvent:\n\t" + e); + } + } + + // --------------------------------------------------- // + + /** + * Bind to debuggee VM using Binder and make initial + * synchronization via IOPipe. + * + * @param argHandler command line arguments handler to make Binder object + * @param log Log object to log messages + * @param mainClassName main class of debugee + * + * @throws Failure if there were problems with binding to debuggee VM + * + * @see Binder#bindToDebugee(String) + */ + public static Debugee prepareDebugee(ArgumentHandler argHandler, Log log, + String mainClassName) { + Binder binder = new Binder(argHandler, log); + Debugee debugee = binder.bindToDebugee(mainClassName); + + debugee.createIOPipe(); + + debugee.redirectStderr(log, DEBUGEE_STDERR_LOG_PREFIX); + debugee.resume(); + + debugee.receiveExpectedSignal("ready"); + + return debugee; + } + + /** + * Send "quit" signal, wait for debugee VM exit and check exit. + * + * @throws Failure if exit status is not Consts.JCK_STATUS_BASE + * + * @see #endDebugee() + */ + public void quit() { + sendSignal("quit"); + int status = endDebugee(); + if ( status != Consts.JCK_STATUS_BASE ) { + throw new Failure("Got unexpected debugee VM exit status: " + status + + " (not " + Consts.JCK_STATUS_BASE + ")"); + } + display("Got expected debugee VM exit status: " + status); + } + + /* + * Dispose debuggee VM, wait for it to exit, close all resources and return + * exit status code. + */ + public int endDebugee() { + if (vm != null) { + try { + vm.dispose(); + } catch (VMDisconnectedException ignore) { + } + vm = null; + } + return waitFor(); + } + + /* + * Print information about all threads in debuggee VM + */ + protected void printThreadsInfo(VirtualMachine vm) { + try { + log.display("------------ Try to print debuggee threads before killing process ------------"); + if (vm == null) { + log.display("Can't print threads info because 'vm' is null"); + return; + } + List threads = vm.allThreads(); + log.display("Threads: " + threads); + log.display("Total threads: " + threads.size()); + for (ThreadReference thread : threads) { + log.display("\nThread: " + thread.name()); + log.display("Is suspended: " + thread.isSuspended()); + log.display("Is at breakpoint: " + thread.isAtBreakpoint()); + boolean wasSuspended = false; + try { + if (!thread.isSuspended()) { + log.display("\n suspend thread to get its stack \n"); + thread.suspend(); + wasSuspended = true; + } + log.display("Stack frame count: " + thread.frameCount()); + if (thread.frameCount() > 0) { + log.display("Frames:"); + for (StackFrame frame : thread.frames()) { + Location location = frame.location(); + log.display(location.declaringType().name() + "." + location.method().name() + ", line: " + location.lineNumber()); + } + } + } finally { + if (wasSuspended) { + log.display("\n resume thread \n"); + thread.resume(); + } + } + } + log.display("----------------------------------------------------------------------"); + } catch (Throwable t) { + log.complain(""); + t.printStackTrace(log.getOutStream()); + } + } + + /** + * Force debugge VM to exit using JDI interface if possible. + */ + protected void killDebugee() { + try { + // print information about debuggee threads to simplify failure analysis + printThreadsInfo(vm); + } finally { + if (vm != null) { + try { + display("Killing debuggee by forcing target VM to exit"); + vm.exit(97); + display("Debugee VM successfully forced to exit"); + vm = null; + } catch (VMDisconnectedException e) { + display("Ignore VMDisconnectedException while forcing debuggee VM to exit:\n\t" + + e); + } + } + } + } + + public boolean isJFR_active() { + String opts = argumentHandler.getLaunchOptions(); + int unlockPos = opts.indexOf("-XX:+UnlockCommercialFeatures"); + int jfrPos = opts.indexOf("-XX:+FlightRecorder"); + + if (unlockPos >= 0 && jfrPos >= 0 && jfrPos > unlockPos) + return true; + else + return false; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggeeEventData.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggeeEventData.java new file mode 100644 index 00000000000..bca9b385652 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggeeEventData.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +/* + * Classes included in this class represent JDI events on debuggee VM's side + * All this classes contain information about JDI event which should be generated during test execution + */ +public class DebuggeeEventData { + // base event data class + public static class DebugEventData { + } + + /* + * debug information about monitor event + */ + public static class DebugMonitorEventData extends DebugEventData { + public DebugMonitorEventData(Object monitor, Thread thread, Object eventObject) { + this.monitor = monitor; + this.thread = thread; + this.eventObject = eventObject; + } + + public Object monitor; + + public Thread thread; + + public Object eventObject; + } + + /* + * information about MonitorContendedEnterEvent + */ + public static class DebugMonitorEnterEventData extends DebugMonitorEventData { + public DebugMonitorEnterEventData(Object monitor, Thread thread, Object eventObject) { + super(monitor, thread, eventObject); + } + } + + /* + * information about MonitorContendedEnteredEvent + */ + public static class DebugMonitorEnteredEventData extends DebugMonitorEventData { + public DebugMonitorEnteredEventData(Object monitor, Thread thread, Object eventObject) { + super(monitor, thread, eventObject); + } + } + + /* + * information about MonitorWaitEvent + */ + public static class DebugMonitorWaitEventData extends DebugMonitorEventData { + public long timeout; + + public DebugMonitorWaitEventData(Object monitor, Thread thread, long timeout, Object eventObject) { + super(monitor, thread, eventObject); + this.timeout = timeout; + } + } + + /* + * information about MonitorWaitedEvent + */ + public static class DebugMonitorWaitedEventData extends DebugMonitorEventData { + public boolean timedout; + + public DebugMonitorWaitedEventData(Object monitor, Thread thread, boolean timedout, Object eventObject) { + super(monitor, thread, eventObject); + this.timedout = timedout; + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggerEventData.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggerEventData.java new file mode 100644 index 00000000000..8d2167b809c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggerEventData.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; + +/* + * Classes included in this class represent JDI events on debugger VM's side + * All this classes contain information about JDI event which should be generated during test execution, + * instances of this classes should be created using instances of corresponding classes from debuggee VM + */ +public class DebuggerEventData +{ + static abstract class DebugEventData + { + + protected Class eventClass; + public DebugEventData(Class eventClass) { + this.eventClass = eventClass; + } + + public boolean shouldCheckEvent(Event event) { + return this.eventClass.isAssignableFrom(event.getClass()); + } + + // is given event's data identical with data stored in this object + abstract public boolean checkEvent(Event event); + } + + /* + * debug information about monitor event + */ + static abstract class DebugMonitorEventData extends DebugEventData { + protected ObjectReference monitor; + + protected ThreadReference thread; + + public DebugMonitorEventData(Class eventClass, ObjectReference debuggeeMirror) { + super(eventClass); + + this.eventClass = eventClass; + monitor = (ObjectReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("monitor")); + thread = (ThreadReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("thread")); + } + + public String toString() { + return eventClass.getName() + " monitor: " + monitor + " thread: " + thread; + } + } + + /* + * information about MonitorContendedEnterEvent + */ + static class DebugMonitorEnterEventData extends DebugMonitorEventData { + public DebugMonitorEnterEventData(ObjectReference debuggeeMirror) { + super(MonitorContendedEnterEvent.class, debuggeeMirror); + } + + public boolean checkEvent(Event event) { + MonitorContendedEnterEvent monitorEnterEvent = (MonitorContendedEnterEvent) event; + + return monitorEnterEvent.monitor().equals(monitor) && monitorEnterEvent.thread().equals(thread); + } + } + + /* + * information about MonitorContendedEnteredEvent + */ + static class DebugMonitorEnteredEventData extends DebugMonitorEventData { + public DebugMonitorEnteredEventData(ObjectReference debuggeeMirror) { + super(MonitorContendedEnteredEvent.class, debuggeeMirror); + } + + public boolean checkEvent(Event event) { + MonitorContendedEnteredEvent monitorEnterEvent = (MonitorContendedEnteredEvent) event; + + return monitorEnterEvent.monitor().equals(monitor) && monitorEnterEvent.thread().equals(thread); + } + } + + /* + * information about MonitorWaitEvent + */ + static class DebugMonitorWaitEventData extends DebugMonitorEventData { + private long timeout; + + public DebugMonitorWaitEventData(ObjectReference debuggeeMirror) { + super(MonitorWaitEvent.class, debuggeeMirror); + + timeout = ((LongValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("timeout"))).longValue(); + } + + public boolean checkEvent(Event event) { + MonitorWaitEvent monitorWaitEvent = (MonitorWaitEvent) event; + + return monitorWaitEvent.monitor().equals(monitor) && monitorWaitEvent.thread().equals(thread) && (monitorWaitEvent.timeout() == timeout); + } + + public String toString() { + return eventClass.getName() + " monitor: " + monitor + " thread: " + thread + " timeout: " + timeout; + } + } + + /* + * information about MonitorWaitedEvent + */ + static class DebugMonitorWaitedEventData extends DebugMonitorEventData { + private boolean timedout; + + public DebugMonitorWaitedEventData(ObjectReference debuggeeMirror) { + super(MonitorWaitedEvent.class, debuggeeMirror); + + timedout = ((BooleanValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("timedout"))).booleanValue(); + } + + public boolean checkEvent(Event event) { + MonitorWaitedEvent monitorWaitedEvent = (MonitorWaitedEvent) event; + + return monitorWaitedEvent.monitor().equals(monitor) && monitorWaitedEvent.thread().equals(thread) + && (monitorWaitedEvent.timedout() == timedout); + } + + public String toString() { + return eventClass.getName() + " monitor: " + monitor + " thread: " + thread + " timedout: " + timedout; + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java new file mode 100644 index 00000000000..74560792ce2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.lang.reflect.*; +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; +import nsk.share.TestBug; + +/* + * EventFilters class just contain all filter classes + */ +public class EventFilters +{ + /* + * Class is intended for testing event filters. + * + * Since different request classes have identical methods for adding filters(e.g. addInstanceFilter(),addClassFilter()) + * but this classes don't have common superclass reflection is used for filter adding. + * Subclasses should implement following methods: + * - getMethodName(), provide filter adding method's name + * - getParametersTypes(), provide filter adding method's parameters types + * - getFilterParameters(), provide parameters to be passed in filter adding method + * + * Also to check is generated event was really filtered subclasses should implement method 'isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)', + * this method should check is event generated by given object in given thread accepted by filter. + */ + public abstract static class DebugEventFilter + { + // eventObject - object which generate event + // eventThread - thread where event was generated + abstract public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread); + + // call corresponding request's method to set event filter + public void addFilter(EventRequest request) + throws Throwable + { + java.lang.reflect.Method method; + + try + { + method = request.getClass().getMethod(getMethodName(), getParametersTypes()); + } + catch(Exception e) + { + throw new TestBug("Can't get method '" + getMethodName() + "'"); + } + + try + { + method.setAccessible(true); + method.invoke(request, getFilterParameters()); + } + catch(IllegalAccessException e) + { + TestBug testBug = new TestBug("Can't call method '" + getMethodName() + "'"); + testBug.initCause(e); + throw testBug; + } + catch(InvocationTargetException e) + { + throw e.getCause(); + } + } + + public boolean isSupported(VirtualMachine vm) + { + return true; + } + + abstract protected String getMethodName(); + abstract protected Class[] getParametersTypes(); + abstract protected Object[] getFilterParameters(); + } + + /* + * Restricts the events to those whose method is in a class whose name matches this + * restricted regular expression. Only simple regular expressions that begin with '*' or end with '*' are supported + */ + public static class ClassFilter + extends DebugEventFilter + { + protected String classPattern; + + private String startsWithPattern; + private String endsWithPattern; + + public ClassFilter(String classPattern) + { + this.classPattern = classPattern; + + if(classPattern.startsWith("*")) + endsWithPattern = classPattern.substring(1); + else + if(classPattern.endsWith("*")) + startsWithPattern = classPattern.substring(0, classPattern.length() - 1); + } + + public String toString() + { + return "ClassFilter: classes should match pattern: " + classPattern; + } + + protected String getMethodName() + { + return "addClassFilter"; + } + + protected Class[] getParametersTypes() + { + return new Class[]{String.class}; + } + + protected Object[] getFilterParameters() + { + return new Object[]{classPattern}; + } + + public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread) + { + if(!isNameMatch(eventObject.referenceType().name())) + return false; + else + return true; + } + + protected boolean isNameMatch(String className) + { + if(startsWithPattern != null) + return className.startsWith(startsWithPattern); + else + if(endsWithPattern != null) + return className.endsWith(endsWithPattern); + else + return className.equals(classPattern); + } + } + + /* + * Restricts the events to those whose method is in a class whose name doesn't matches + * restricted regular expression. Only simple regular expressions that begin with '*' or end with '*' are supported + */ + public static class ClassExclusionFilter + extends ClassFilter + { + public ClassExclusionFilter(String classPattern) + { + super(classPattern); + } + + public String toString() + { + return "ClassExclusionFilter: classes match follows pattern should be excluded: " + classPattern; + } + + protected String getMethodName() + { + return "addClassExclusionFilter"; + } + + public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread) + { + if(isNameMatch(eventObject.referenceType().name())) + return false; + else + return true; + } + } + + /* + * Restricts the events to those whose method is in the given reference type or any of its subtypes + */ + public static class ClassReferenceFilter + extends DebugEventFilter + { + private Class filterClass; + private ReferenceType referenceType; + + public ClassReferenceFilter(ReferenceType referenceType) + { + this.referenceType = referenceType; + filterClass = findClass(referenceType); + } + + public String toString() + { + return "ClassReferenceFilter: expect only " + filterClass.getName() + " and its subclasses"; + } + + protected String getMethodName() + { + return "addClassFilter"; + } + + protected Class[] getParametersTypes() + { + return new Class[]{ReferenceType.class}; + } + + protected Object[] getFilterParameters() + { + return new Object[]{referenceType}; + } + + public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread) + { + Class eventObjectClass = findClass(eventObject.referenceType()); + + if(!filterClass.isAssignableFrom(eventObjectClass)) + return false; + else + return true; + } + + // find class represented by given referenceType + private Class findClass(ReferenceType referenceType) + { + try + { + return Class.forName(referenceType.name()); + } + catch(ClassNotFoundException e) + { + throw new TestBug("Can't find class: " + referenceType.name()); + } + } + } + + /* + * Restricts the events to those in which the currently executing instance ("this") is the given object + */ + public static class ObjectReferenceFilter + extends DebugEventFilter + { + private ObjectReference objectReference; + + public ObjectReferenceFilter(ObjectReference objectReference) + { + this.objectReference = objectReference; + } + + public String toString() + { + return "ObjectReferenceFilter: expect only object " + objectReference; + } + + protected String getMethodName() + { + return "addInstanceFilter"; + } + + protected Class[] getParametersTypes() + { + return new Class[]{ObjectReference.class}; + } + + protected Object[] getFilterParameters() + { + return new Object[]{objectReference}; + } + + public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread) + { + return objectReference.equals(eventObject); + } + + public boolean isSupported(VirtualMachine vm) + { + return vm.canUseInstanceFilters(); + } + } + + /* + * Restricts the events to those in the given thread + */ + public static class ThreadFilter + extends DebugEventFilter + { + private ThreadReference threadReference; + + public ThreadFilter(ThreadReference threadReference) + { + this.threadReference = threadReference; + } + + public String toString() + { + return "ThreadReferenceFilter: expect only thread " + threadReference; + } + + protected String getMethodName() + { + return "addThreadFilter"; + } + + protected Class[] getParametersTypes() + { + return new Class[]{ThreadReference.class}; + } + + protected Object[] getFilterParameters() + { + return new Object[]{threadReference}; + } + + public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread) + { + return threadReference.equals(eventThread); + } + } + + public static boolean filtered(Event event) { + if (event.toString().contains("VM JFR Buffer Thread")) + return true; + + if (event.toString().contains("JFR request timer")) + return true; + + return false; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java new file mode 100644 index 00000000000..e9735a13767 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import java.util.*; +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; +import nsk.share.*; + +/** + * This class provides a separate thread for asynchronous listening + * to JDI events. All received events are sequentially passed + * to event listeners. If current event listener returns true + * then the event is considered be processed and it is not passed + * to remaining listeners. + *

      + * The EventHandler thread runs until VMDisconnectEvent + * is received or VMDisconnectionedException is caught. + * + * @see EventListener + */ +public class EventHandler implements Runnable { + + private Debugee debuggee = null; + private Log log = null; + + private VirtualMachine vm; + private EventRequestManager requestManager; + /** + * Container for event listeners + */ + private static List listeners = Collections.synchronizedList(new Vector()); + private Thread listenThread; + + /** + * Exit status of the EventHandler thread + */ + private static volatile int status = -1; + + /** + * Return an exit status of the EventHandler thread + * were the values are: + *

    • -1 - no value + *
    • 0 - normal termination + *
    • 1 - the thread is still running + *
    • 2 - abnormal termination + */ + public static synchronized int getStatus() { + return status; + } + + /** + * Default ExceptionRequest with SUSPEND_EVENT_THREAD to be able + * to catch debuggee exceptions and output a message. + */ + private static ExceptionRequest defaultExceptionRequest = null; + + /** + * This flag will be set true if event of uncaught exception has been + * received. + */ + private static volatile boolean defaultExceptionCaught = false; + public static synchronized boolean getExceptionCaught() { + return defaultExceptionCaught; + } + + /** + * This flag will be set true if any event which does not have specific + * listener has been received. + */ + private static volatile boolean unexpectedEventCaught = false; + public static synchronized boolean unexpectedEventCaught() { + return unexpectedEventCaught; + } + + /** + * This flag shows if debugged VM is connected to debugger. + */ + private static volatile boolean vmDisconnected = false; + public static synchronized boolean isDisconnected() { + return vmDisconnected; + } + + public EventHandler(Debugee debuggee, Log log) { + this.listenThread = new Thread(this); + this.listenThread.setDaemon(true); + + this.debuggee = debuggee; + this.log = log; + this.vm = debuggee.VM(); + this.requestManager = vm.eventRequestManager(); + } + + private void display(String str) { + log.display("EventHandler> " + str); + } + + // is EventHandler was interrupted + private volatile boolean wasInterrupted; + + public void stopEventHandler() { + wasInterrupted = true; + + listenThread.interrupt(); + + try { + listenThread.join(); + } + catch(InterruptedException e) { + throw new TestBug("Unexpected exception: " + e); + } + } + /** + * The EventHandler thread keeps running until a VMDisconnectedEvent occurs + * or some exception occurs during event processing. + */ + public void run() { + synchronized(EventHandler.this) { + status = 1; // running + } + do { + try { + EventSet set = vm.eventQueue().remove(); + + switch (set.suspendPolicy()) { + case EventRequest.SUSPEND_NONE: + display("Received event set with policy = SUSPEND_NONE"); + break; + case EventRequest.SUSPEND_ALL: + display("Received event set with policy = SUSPEND_ALL"); + break; + case EventRequest.SUSPEND_EVENT_THREAD: + display("Received event set with policy = SUSPEND_EVENT_THREAD"); + break; + } + + synchronized (listeners) { + synchronized (EventHandler.this) { + for (EventListener listener : listeners) { + // proloque listener for a event set + listener.eventSetReceived(set); + } + + for (Event event : set) { + // print only event class name here because of Event,toString may cause unexpected exception + display("Event: " + event.getClass().getSimpleName() + + " req " + event.request()); + boolean processed = false; + for (EventListener listener : listeners) { + processed = listener.eventReceived(event); + + if (processed) { + if (listener.shouldRemoveListener()) { + listener.eventSetComplete(set); + removeListener(listener); + } + + break; + } + } + } + + for (EventListener listener : listeners) { + // epiloque listener for a event set + listener.eventSetComplete(set); + } + } + } + + } + catch (Exception e) { + + if(e instanceof InterruptedException) { + if(wasInterrupted) + break; + } + + log.complain("Exception occured in eventHandler thread: " + e.getMessage()); + e.printStackTrace(log.getOutStream()); + synchronized(EventHandler.this) { + // This will make the waiters such as waitForVMDisconnect + // exit their wait loops. + vmDisconnected = true; + status = 2; // abnormal termination + EventHandler.this.notifyAll(); + } + throw new Failure(e); + } + } while (!wasInterrupted && !isDisconnected()); + + if (unexpectedEventCaught || defaultExceptionCaught) { + synchronized(EventHandler.this) { + status = 2; + } + } + display("finished"); + } + + + /** + * This is normally called in the main thread of the test debugger. + * It starts up an EventHandler thread that gets events coming in + * from the debuggee and distributes them to listeners. + */ + public void startListening() { + createDefaultEventRequests(); + createDefaultListeners(); + listenThread.start(); + } + + + /** + * This method sets up default requests. + */ + private void createDefaultEventRequests() { + /** + * The following request will allow to print a warning if a debuggee gets an + * unexpected exception. The unexpected exception will be handled in + * the eventReceived method in the default listener created. + * If a test case does not want an uncaught exception to cause a + * message, it must add new listener for uncaught exception events to + * handle them. + */ + defaultExceptionRequest = requestManager.createExceptionRequest(null, false, true); + defaultExceptionRequest.enable(); + } + + /** + * This method sets up default listeners. + */ + private void createDefaultListeners() { + /** + * This listener catches up all unexpected events. + * + */ + addListener( + new EventListener() { + public boolean eventReceived(Event event) { + log.complain("EventHandler> Unexpected event: " + event.getClass().getName()); + unexpectedEventCaught = true; + return true; + } + } + ); + + /** + * This listener catches up VMStart event. + */ + addListener( + new EventListener() { + public boolean eventReceived(Event event) { + if (event instanceof VMStartEvent) { + display("received VMStart"); + removeListener(this); + return true; + } + return false; + } + } + ); + + /** + * This listener catches up VMDeath event. + */ + addListener( + new EventListener() { + public boolean eventReceived(Event event) { + if (event instanceof VMDeathEvent) { + display("receieved VMDeath"); + removeListener(this); + return true; + } + return false; + } + } + ); + + /** + * This listener catches up VMDisconnectEventevent and + * signals EventHandler thread to finish. + */ + addListener( + new EventListener() { + public boolean eventReceived(Event event) { + if (event instanceof VMDisconnectEvent ) { + display("receieved VMDisconnect"); + synchronized(EventHandler.this) { + vmDisconnected = true; + status = 0; // OK finish + EventHandler.this.notifyAll(); + removeListener(this); + } + return true; + } + return false; + } + } + ); + + /** + * This listener catches uncaught exceptions and print a message. + */ + addListener( new EventListener() { + public boolean eventReceived(Event event) { + boolean handled = false; + + if (event instanceof ExceptionEvent && + defaultExceptionRequest != null && + defaultExceptionRequest.equals(event.request())) { + + if (EventFilters.filtered(event) == false) { + log.complain("EventHandler> Unexpected Debuggee Exception: " + + (ExceptionEvent)event); + defaultExceptionCaught = true; + } + + handled = true; + vm.resume(); + } + + return handled; + } + } + ); + } + + /** + * Add at beginning of the list because we want + * the LAST added listener to be FIRST to process + * current event. + */ + public void addListener(EventListener listener) { + display("Adding listener " + listener); + synchronized(listeners) { + listeners.add(0, listener); + } + } + + /** + * Removes the listener from the list. + */ + public void removeListener(EventListener listener) { + display("Removing listener " + listener); + synchronized(listeners) { + listeners.remove(listener); + } + } + + + /** + * Returns an event which is received for any of given requests. + */ + public Event waitForRequestedEvent( final EventRequest[] requests, + long timeout, + boolean shouldRemoveListeners) { + class EventNotification { + volatile Event event = null; + } + final EventNotification en = new EventNotification(); + + EventListener listener = new EventListener() { + public boolean eventReceived(Event event) { + for (int i = 0; i < requests.length; i++) { + EventRequest request = requests[i]; + if (!request.isEnabled()) + continue; + if (request.equals(event.request())) { + display("waitForRequestedEvent: Received event(" + event + ") for request(" + request + ")"); + synchronized (EventHandler.this) { + en.event = event; + EventHandler.this.notifyAll(); + } + return true; + } + } + return false; + } + }; + if (shouldRemoveListeners) { + display("waitForRequestedEvent: enabling remove of listener " + listener); + listener.enableRemovingThisListener(); + } + for (int i = 0; i < requests.length; i++) { + requests[i].enable(); + } + addListener(listener); + + try { + long timeToFinish = System.currentTimeMillis() + timeout; + long timeLeft = timeout; + synchronized (EventHandler.this) { + display("waitForRequestedEvent: vm.resume called"); + vm.resume(); + + while (!isDisconnected() && en.event == null && timeLeft > 0) { + EventHandler.this.wait(timeLeft); + timeLeft = timeToFinish - System.currentTimeMillis(); + } + } + } catch (InterruptedException e) { + return null; + } + if (shouldRemoveListeners && !isDisconnected()) { + for (int i = 0; i < requests.length; i++) { + requests[i].disable(); + } + } + if (en.event == null) { + throw new Failure("waitForRequestedEvent: no requested events have been received."); + } + return en.event; + } + + /** + * Returns an event set which is received for any of given requests. + */ + public EventSet waitForRequestedEventSet( final EventRequest[] requests, + long timeout, + boolean shouldRemoveListeners) { + class EventNotification { + volatile EventSet set = null; + } + final EventNotification en = new EventNotification(); + + EventListener listener = new EventListener() { + public void eventSetReceived(EventSet set) { + + EventIterator eventIterator = set.eventIterator(); + + while (eventIterator.hasNext()) { + + Event event = eventIterator.nextEvent(); + + for (int i = 0; i < requests.length; i++) { + EventRequest request = requests[i]; + if (!request.isEnabled()) + continue; + + if (request.equals(event.request())) { + display("waitForRequestedEventSet: Received event set for request: " + request); + synchronized (EventHandler.this) { + en.set = set; + EventHandler.this.notifyAll(); + } + return; + } + } + } + } + + public boolean eventReceived(Event event) { + return (en.set != null); + } + }; + + if (shouldRemoveListeners) { + display("waitForRequestedEventSet: enabling remove of listener " + listener); + listener.enableRemovingThisListener(); + } + for (int i = 0; i < requests.length; i++) { + requests[i].enable(); + } + addListener(listener); + + try { + long timeToFinish = System.currentTimeMillis() + timeout; + long timeLeft = timeout; + synchronized (EventHandler.this) { + display("waitForRequestedEventSet: vm.resume called"); + vm.resume(); + + while (!isDisconnected() && en.set == null && timeLeft > 0) { + EventHandler.this.wait(timeLeft); + timeLeft = timeToFinish - System.currentTimeMillis(); + } + } + } catch (InterruptedException e) { + return null; + } + if (shouldRemoveListeners && !isDisconnected()) { + for (int i = 0; i < requests.length; i++) { + requests[i].disable(); + } + } + if (en.set == null) { + throw new Failure("waitForRequestedEventSet: no requested events have been received."); + } + return en.set; + } + + public synchronized void waitForVMDisconnect() { + display("waitForVMDisconnect"); + while (!isDisconnected()) { + try { + wait(); + } catch (InterruptedException e) { + } + } + display("waitForVMDisconnect: done"); + } + + /** + * This is a superclass for any event listener. + */ + public static class EventListener { + + /** + * This flag shows if the listener must be removed + * after current event has been processed by + * this listener. + */ + volatile boolean shouldRemoveListener = false; + public boolean shouldRemoveListener() { + return shouldRemoveListener; + } + + public void enableRemovingThisListener() { + shouldRemoveListener = true; + } + + /** + * This method will be called by EventHandler + * for received event set before any call of eventReceived + * method for events contained in this set. + */ + public void eventSetReceived(EventSet set) {} + + + /** + * This method will be called by EventHandler + * for received event set after all calls of eventReceived + * and event specific methods for all events contained in this set. + */ + public void eventSetComplete(EventSet set) {} + + /** + * This method will be called by EventHandler + * for any event contained in received event set. + * + * @return true if event was processed by this + * EventListener or false otherwise. + */ + public boolean eventReceived(Event event) { + return false; + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventTestTemplates.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventTestTemplates.java new file mode 100644 index 00000000000..727ff82dff7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventTestTemplates.java @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.*; +import java.util.*; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import nsk.share.Consts; +import nsk.share.TestBug; + +/* + * Class contains debugger classes based on JDIEventsDebugger intended for JDI events testing + */ +public class EventTestTemplates { + + // how many times rerun test in case when tested events aren't generated + static final int MAX_TEST_RUN_NUMBER = 10; + + /* + * Method contains common code used by EventFilterTests and StressTestTemplate + */ + static void runTestWithRerunPossibilty(JDIEventsDebugger debugger, Runnable testRunner) { + for (int i = 0; i < MAX_TEST_RUN_NUMBER; i++) { + testRunner.run(); + + /* + * If events weren't generated at all but test accepts missing events + * try to rerun test (rerun test only if it didn't fail yet) + */ + if (debugger.eventsNotGenerated() && debugger.getSuccess()) { + if (i < MAX_TEST_RUN_NUMBER - 1) { + debugger.log.display("\nWARNING: tested events weren't generated at all, trying to rerun test (rerun attempt " + (i + 1) + ")\n"); + continue; + } else { + debugger.setSuccess(false); + debugger.log.complain("Tested events weren't generated after " + MAX_TEST_RUN_NUMBER + " runs, test FAILED"); + } + } else + break; + } + } + + /* + * Debugger class for testing event filters, subclasses should parse command + * line and call method JDIEventsDebugger.eventFilterTestTemplate with + * required arguments. + * + * Class handles common for event filter tests parameters: + * - debuggee class name (e.g. -debuggeeClassName nsk.share.jdi.MonitorEventsDebuggee) + * - tested event type (e.g. -eventType MONITOR_CONTENTED_ENTER) + */ + public static abstract class EventFilterTest extends JDIEventsDebugger { + protected String debuggeeClassName; + + protected EventType eventType; + + protected String[] doInit(String[] args, PrintStream out) { + args = super.doInit(args, out); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-debuggeeClassName") && (i < args.length - 1)) { + debuggeeClassName = args[i + 1]; + i++; + } else if (args[i].equals("-eventType") && (i < args.length - 1)) { + try { + eventType = EventType.valueOf(args[i + 1]); + } catch (IllegalArgumentException e) { + TestBug testBug = new TestBug("Invalid event type : " + args[i + 1], e); + throw testBug; + } + i++; + } else + standardArgs.add(args[i]); + } + + if (eventType == null) + throw new TestBug("Test requires 'eventType' parameter"); + + if (debuggeeClassName == null) + throw new TestBug("Test requires 'debuggeeClassName' parameter"); + + return standardArgs.toArray(new String[] {}); + } + + abstract protected int getTestFiltersNumber(); + + // This class is required to call runTestWithRerunPossibilty() + class FilterTestRunner implements Runnable { + private int filterIndex; + + FilterTestRunner(int filterIndex) { + this.filterIndex = filterIndex; + } + + public void run() { + eventFilterTestTemplate(eventType, filterIndex); + } + } + + public final void doTest() { + prepareDebuggee(new EventType[] {eventType}); + + int filtersNumber = getTestFiltersNumber(); + + if (filtersNumber <= 0) + throw new TestBug("Invalid filtersNumber: " + filtersNumber); + + for (int filterIndex = 0; filterIndex < getTestFiltersNumber(); filterIndex++) { + runTestWithRerunPossibilty(this, new FilterTestRunner(filterIndex)); + } + + eventHandler.stopEventHandler(); + removeDefaultBreakpoint(); + } + + // can't control events from system libraries, so save events only from nsk packages + protected boolean shouldSaveEvent(Event event) { + return isEventFromNSK(event); + } + + protected String debuggeeClassName() { + return debuggeeClassName; + } + } + + /* + * Class for testing class exclusion filter, this filter is added by + * request's method addClassExclusionFilter(String classPattern) Expected + * command line parameter: + * - class patterns which should be passed to adding filter method (e.g. -classPatterns java.*:*.Foo) + */ + public static class ClassExclusionFilterTest extends EventFilterTest { + protected String classPatterns[]; + + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new ClassExclusionFilterTest().runIt(argv, out); + } + + protected String[] doInit(String[] args, PrintStream out) { + args = super.doInit(args, out); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-classPatterns") && (i < args.length - 1)) { + classPatterns = args[i + 1].split(":"); + i++; + } else + standardArgs.add(args[i]); + } + + if (classPatterns == null || classPatterns.length == 0) + throw new TestBug("Test requires at least one class name pattern"); + + return standardArgs.toArray(new String[] {}); + } + + protected int getTestFiltersNumber() { + return classPatterns.length; + } + + protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) { + if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length) + throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex); + + return new EventFilters.DebugEventFilter[]{new EventFilters.ClassExclusionFilter(classPatterns[testedFilterIndex])}; + } + } + + /* + * Subclass of ClassExclusionFilterTest, create ClassFilter instead of + * ClassExclusionFilter, this filter is added by request's method + * addClassFilter(String classPattern) + */ + public static class ClassFilterTest_ClassName extends ClassExclusionFilterTest { + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new ClassFilterTest_ClassName().runIt(argv, out); + } + + protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) { + if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length) + throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex); + + return new EventFilters.DebugEventFilter[]{new EventFilters.ClassFilter(classPatterns[testedFilterIndex])}; + } + } + + /* + * Subclass of ClassExclusionFilterTest, create ClassReferenceFilter instead + * of ClassExclusionFilter, this filter is added by request's method + * addClassFilter(ReferenceType referenceType) + */ + public static class ClassFilterTest_ReferenceType extends ClassExclusionFilterTest { + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new ClassFilterTest_ReferenceType().runIt(argv, out); + } + + protected int getTestFiltersNumber() { + return classPatterns.length; + } + + protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) { + if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length) + throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex); + + ReferenceType referenceType = debuggee.classByName(classPatterns[testedFilterIndex]); + if (referenceType == null) + throw new TestBug("Invalid class name is passed: " + classPatterns[testedFilterIndex]); + + return new EventFilters.DebugEventFilter[]{new EventFilters.ClassReferenceFilter(referenceType)}; + } + } + + /* + * Class for testing instance filter, this filter is added by request's + * method addInstanceFilter(ObjectReference instance). Class tests 3 following + * cases: + * - add filter for single object + * - add filter for the same object 2 times, expect behavior such as in previous case + * - add filter for 2 different objects, so events shouldn't be received + */ + public static class InstanceFilterTest extends EventFilterTest { + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new InstanceFilterTest().runIt(argv, out); + } + + protected int getTestFiltersNumber() { + return 3; + } + + protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) { + List objects = getEventObjects(); + + if (objects.size() < 2) { + throw new TestBug("Debuggee didn't create event generating objects"); + } + + switch (testedFilterIndex) { + case 0: + // filter for 1 object + return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0))}; + case 1: + // add 2 filters for the same object + return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0)), + new EventFilters.ObjectReferenceFilter(objects.get(0))}; + case 2: + // add 2 filters for 2 different objects, so don't expect any event + return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0)), + new EventFilters.ObjectReferenceFilter(objects.get(1))}; + default: + throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex); + } + } + } + + /* + * Class for testing thread filter, this filter is added by request's method + * addThreadFilter(ThreadReference thread). Class test 3 follows cases: + * - add filter for single thread + * - add filter for the same thread 2 times, expect behavior such as in previous case + * - add filter for 2 different threads, so events shouldn't be received + */ + public static class ThreadFilterTest extends EventFilterTest { + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new ThreadFilterTest().runIt(argv, out); + } + + protected int getTestFiltersNumber() { + return 3; + } + + protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) { + List threads = getEventThreads(); + + if (threads.size() < 2) { + throw new TestBug("Debuggee didn't create event generating threads"); + } + + switch (testedFilterIndex) { + case 0: + // filter for 1 thread + return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0))}; + case 1: + // add 2 filters for the same thread + return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0)), + new EventFilters.ThreadFilter(threads.get(0))}; + case 2: + // add 2 filters for 2 different threads, so don't expect any event + return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0)), + new EventFilters.ThreadFilter(threads.get(1))}; + default: + throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex); + } + } + } + + /* + * Class is intended for stress testing, expected command line parameters: + * - debuggee class name (e.g.: -debuggeeClassName nsk.share.jdi.MonitorEventsDebuggee) + * - one or more tested event types (e.g.: -eventTypes MONITOR_CONTENTED_ENTER:MONITOR_CONTENTED_ENTERED) + * - number of events which should be generated during test execution (e.g.: -eventsNumber 500) + * - number of threads which simultaneously generate events (e.g.: -threadsNumber 10) + * + * Class parses command line and calls method JDIEventsDebugger.stressTestTemplate. + */ + public static class StressTestTemplate extends JDIEventsDebugger { + protected String debuggeeClassName; + + protected EventType testedEventTypes[]; + + protected int eventsNumber = 1; + + protected int threadsNumber = 1; + + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new StressTestTemplate().runIt(argv, out); + } + + protected String[] doInit(String[] args, PrintStream out) { + args = super.doInit(args, out); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-eventsNumber") && (i < args.length - 1)) { + eventsNumber = Integer.parseInt(args[i + 1]); + + // for this stress test events number is equivalent of iterations + // (don't support 0 value of IterationsFactor) + if (stressOptions.getIterationsFactor() != 0) + eventsNumber *= stressOptions.getIterationsFactor(); + + i++; + } else if (args[i].equals("-threadsNumber") && (i < args.length - 1)) { + threadsNumber = Integer.parseInt(args[i + 1]); + + // if 'threadsNumber' is specified test should take in account stress options + threadsNumber *= stressOptions.getThreadsFactor(); + + i++; + } else if (args[i].equals("-debuggeeClassName") && (i < args.length - 1)) { + debuggeeClassName = args[i + 1]; + i++; + } else if (args[i].equals("-eventTypes") && (i < args.length - 1)) { + String eventTypesNames[] = args[i + 1].split(":"); + testedEventTypes = new EventType[eventTypesNames.length]; + try { + for (int j = 0; j < eventTypesNames.length; j++) + testedEventTypes[j] = EventType.valueOf(eventTypesNames[j]); + } catch (IllegalArgumentException e) { + throw new TestBug("Invalid event type", e); + } + + i++; + } else + standardArgs.add(args[i]); + } + + if (testedEventTypes == null || testedEventTypes.length == 0) + throw new TestBug("Test requires 'eventTypes' parameter"); + + if (debuggeeClassName == null) + throw new TestBug("Test requires 'debuggeeClassName' parameter"); + + return standardArgs.toArray(new String[] {}); + } + + // can't control events from system libraries, so save events only from nsk packages + protected boolean shouldSaveEvent(Event event) { + return isEventFromNSK(event); + } + + protected String debuggeeClassName() { + return debuggeeClassName; + } + + public void doTest() { + prepareDebuggee(testedEventTypes); + + runTestWithRerunPossibilty(this, new Runnable() { + public void run() { + stressTestTemplate(testedEventTypes, eventsNumber, threadsNumber); + } + }); + + eventHandler.stopEventHandler(); + removeDefaultBreakpoint(); + } + } + + static public boolean isEventFromNSK(Event event) { + if (event instanceof MonitorContendedEnterEvent) { + return ((MonitorContendedEnterEvent) event).location() != null && ((MonitorContendedEnterEvent) event).monitor().type().name().startsWith("nsk."); + } + if (event instanceof MonitorContendedEnteredEvent) { + return ((MonitorContendedEnteredEvent) event).location() != null && ((MonitorContendedEnteredEvent) event).monitor().type().name().startsWith("nsk."); + } + if (event instanceof MonitorWaitEvent) { + return ((MonitorWaitEvent) event).monitor().type().name().startsWith("nsk."); + } + if (event instanceof MonitorWaitedEvent) { + return ((MonitorWaitedEvent) event).monitor().type().name().startsWith("nsk."); + } + + // don't filter other events + return true; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ForceEarlyReturnDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ForceEarlyReturnDebugger.java new file mode 100644 index 00000000000..7b5d58828f4 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ForceEarlyReturnDebugger.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +/* + * Class contains methods common for nsk/jdi/ThreadReference/forceEarlyReturn tests + */ +public class ForceEarlyReturnDebugger extends TestDebuggerType2 { + protected boolean canRunTest() { + if (!vm.canForceEarlyReturn()) { + log.display("TEST CANCELED due to: vm.canForceEarlyReturn() = false"); + return false; + } else + return super.canRunTest(); + } + + protected void testMethodExitEvent(ThreadReference thread, String methodName) { + testMethodExitEvent(thread, methodName, true); + } + + /* + * Method for checking is after forceEarlyReturn MethodExitEvent is generated as it would be in a normal return + * Before calling this method forceEarlyReturn() should be already called and tested thread should be suspended + */ + protected void testMethodExitEvent(ThreadReference thread, String methodName, boolean resumeThreadAfterEvent) { + MethodExitRequest methodExitRequest; + methodExitRequest = debuggee.getEventRequestManager().createMethodExitRequest(); + methodExitRequest.addThreadFilter(thread); + methodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + methodExitRequest.enable(); + + EventListenerThread listenerThread = new EventListenerThread(methodExitRequest); + listenerThread.start(); + listenerThread.waitStartListen(); + + thread.resume(); + + Event event = listenerThread.getEvent(); + + if (event == null) { + setSuccess(false); + log.complain("MethodExitEvent was not generated " + ", method: " + methodName); + } else { + if (!((MethodExitEvent) event).method().name().equals(methodName)) { + setSuccess(false); + log.complain("Invalid MethodExitEvent: expected method - " + methodName + ", actually - " + + ((MethodExitEvent) event).method().name()); + } + } + + methodExitRequest.disable(); + vm.eventRequestManager().deleteEventRequest(methodExitRequest); + + if (resumeThreadAfterEvent) + thread.resume(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java new file mode 100644 index 00000000000..6f48ac16003 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.*; +import java.util.*; +import nsk.share.Log; +import nsk.share.ObjectInstancesManager; +import nsk.share.TestBug; +import nsk.share.jpda.DebugeeArgumentHandler; +import nsk.share.jpda.IOPipe; + +/* + * Debuggee class used in tests for heapwalking(tests for VirtualMachine.instanceCounts, ReferenceType.instances, ObjectReference.referrers). + * Handle commands related to creation of objects instances with given reference type + * and given referrers number, use for this purposes nsk.share.ObjectInstancesManager. + */ +public class HeapwalkingDebuggee extends AbstractJDIDebuggee { + protected ObjectInstancesManager objectInstancesManager; + + // reference of this type should be included in ObjectReference.referringObjects + public static Set includedIntoReferrersCountTypes = new HashSet(); + + // reference of this type should be included in ReferenceType.instances + public static Set includedIntoInstancesCountTypes = new HashSet(); + + static { + includedIntoInstancesCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE); + includedIntoInstancesCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE); + includedIntoInstancesCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE); + includedIntoInstancesCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE); + includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_GLOBAL_REFERENCE); + includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_LOCAL_REFERENCE); + + includedIntoReferrersCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE); + includedIntoReferrersCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE); + includedIntoReferrersCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE); + includedIntoReferrersCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE); + } + + //create number instance of class with given name, command format: createInstances:class_name:instance_count[:referrer_count:referrer_type] + static public final String COMMAND_CREATE_INSTANCES = "createInstances"; + + //'delete'(make unreachable) number instance of class with given name, command format: deleteInstances:class_name:instance_count:referrer_count + static public final String COMMAND_DELETE_INSTANCES = "deleteInstances"; + + //delete number referrers + static public final String COMMAND_DELETE_REFERRERS = "deleteReferrers"; + + //create instance with all type referrers + static public final String COMMAND_CREATE_ALL_TYPE_REFERENCES = "createAllTypeReferences"; + + protected void init(String args[]) { + super.init(args); + objectInstancesManager = new ObjectInstancesManager(log); + } + + public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String args[], boolean callExit) { + super.initDebuggee(argHandler, log, pipe, args, callExit); + objectInstancesManager = new ObjectInstancesManager(log); + } + + public boolean parseCommand(String command) { + if (super.parseCommand(command)) + return true; + + try { + StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command)); + tokenizer.whitespaceChars(':', ':'); + tokenizer.wordChars('_', '_'); + tokenizer.wordChars('$', '$'); + tokenizer.wordChars('[', ']'); + tokenizer.wordChars('|', '|'); + + if (command.startsWith(COMMAND_CREATE_INSTANCES)) { + //createInstances:class_name:instance_count[:referrer_count:referrer_type] + + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String className = tokenizer.sval; + + if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) + throw new TestBug("Invalid command format: " + command); + + int instanceCounts = (int) tokenizer.nval; + + int referrerCount = 1; + Set referrerType = new HashSet(); + + if (tokenizer.nextToken() == StreamTokenizer.TT_NUMBER) { + referrerCount = (int) tokenizer.nval; + + if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) + referrerType.addAll(Arrays.asList(tokenizer.sval.split("\\|"))); + } + if (referrerType.isEmpty()) { + referrerType.add(ObjectInstancesManager.STRONG_REFERENCE); + } + + objectInstancesManager.createReferences(instanceCounts, className, referrerCount, referrerType); + + return true; + } else if (command.startsWith(COMMAND_DELETE_INSTANCES)) { + //deleteInstances:class_name:instance_count:referrer_count + + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String className = tokenizer.sval; + + if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) + throw new TestBug("Invalid command format: " + command); + + int instanceCounts = (int) tokenizer.nval; + + objectInstancesManager.deleteAllReferrers(instanceCounts, className); + + return true; + } else if (command.startsWith(COMMAND_DELETE_REFERRERS)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String className = tokenizer.sval; + + if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) + throw new TestBug("Invalid command format: " + command); + + int referrersCount = (int) tokenizer.nval; + + Set referrerTypes = new HashSet(); + if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) { + referrerTypes.addAll(Arrays.asList(tokenizer.sval.split("\\|"))); + } + + objectInstancesManager.deleteReferrers(className, referrersCount, referrerTypes); + + return true; + } else if (command.startsWith(COMMAND_CREATE_ALL_TYPE_REFERENCES)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String className = tokenizer.sval; + + if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) + throw new TestBug("Invalid command format: " + command); + + int instanceCounts = (int) tokenizer.nval; + + objectInstancesManager.createAllTypeReferences(className, instanceCounts); + + return true; + } + } catch (IOException e) { + throw new TestBug("Invalid command format: " + command); + } + + return false; + } + + // instances of some classes couldn't be strictly controlled during test execution, use non-strict checks for this classes + public static boolean useStrictCheck(String className, boolean otherThreadPresent) { + if (className.equals("java.lang.String")) + return false; + + if (className.equals("char[]")) + return false; + + if (className.equals("byte[]")) + return false; + + if (className.equals("java.lang.Thread")) { + if (otherThreadPresent) + return false; + } + + return true; + } + + // is reference with given type should be included in ObjectReference.referringObjects + static public boolean isIncludedIntoReferrersCount(String referenceType) { + if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) { + throw new TestBug("Invalid reference type: " + referenceType); + } + + return includedIntoReferrersCountTypes.contains(referenceType); + } + + // is reference with given type should be included in ReferenceType.instances + static public boolean isIncludedIntoInstancesCount(String referenceType) { + if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) { + throw new TestBug("Invalid reference type: " + referenceType); + } + + return includedIntoInstancesCountTypes.contains(referenceType); + } + + public static void main(String args[]) { + HeapwalkingDebuggee debuggee = new HeapwalkingDebuggee(); + debuggee.init(args); + debuggee.doTest(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebugger.java new file mode 100644 index 00000000000..d68b5a92d5a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebugger.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.util.*; +import com.sun.jdi.*; +import nsk.share.TestBug; + +/* + * Debugger class used in tests for heapwalking(tests for VirtualMachine.instanceCounts, ReferenceType.instances, ObjectReference.referrers) + * Contains several common checking and auxiliary methods. + */ +public class HeapwalkingDebugger extends TestDebuggerType2 { + // instances of some classes couldn't be strictly controlled during test execution, use non-strict checks for this classes + protected boolean strictCheck(String className) { + boolean otherThreadPresent = isJFR_active(); + return HeapwalkingDebuggee.useStrictCheck(className, otherThreadPresent); + } + + // wrapper for VirtualMachine.instanceCounts + public long getInstanceCount(String className) { + List list = vm.classesByName(className); + + if (list.size() == 0) + return 0; + + if (list.size() > 1) { + setSuccess(false); + log.complain("Unexpected collection size returned by VirtualMachine.classesByName(" + className + "): " + list.size() + + ", only 1 entry was expected."); + } + + long result[] = (vm.instanceCounts(list)); + + return result[0]; + } + + // tests that vm.instanceCounts(vm.allClasses()) doesn't throws any exceptions + protected void testInstanceCounts() { + try { + vm.instanceCounts(vm.allClasses()); + } catch (Throwable t) { + setSuccess(false); + log.complain("Unexpected exception: " + t); + t.printStackTrace(log.getOutStream()); + } + + } + + // check size of list returned by ReferenceType.instances + protected void checkDebugeeAnswer_instances(String className, int expectedCount) { + ReferenceType referenceType = debuggee.classByName(className); + + int instanceCounts = referenceType.instances(0).size(); + + if (strictCheck(className)) { + if (referenceType.instances(0).size() != expectedCount) { + setSuccess(false); + log.complain("Unexpected size of referenceType.instances(" + className + "): " + instanceCounts + ", expected: " + expectedCount); + } + } else { + if (referenceType.instances(0).size() < expectedCount) { + setSuccess(false); + log.complain("Unexpected size of referenceType.instances(" + className + "): " + instanceCounts + ", expected: >= " + expectedCount); + } + } + } + + // check value returned by VirtualMachine.instanceCounts, + // note that method call method isDebuggeeReady() which check that debuggee completed pervious command and is ready for new one + public void checkDebugeeAnswer_instanceCounts(String className, int expectedValue) { + if (!isDebuggeeReady()) + return; + + try { + long instanceCounts = getInstanceCount(className); + + if (strictCheck(className)) { + if (instanceCounts != expectedValue) { + setSuccess(false); + log.complain("Wrong value was returned by VirtualMachine.instanceCounts(" + className + "): " + instanceCounts + ", expected: " + + expectedValue); + } + } else { + if (instanceCounts < expectedValue) { + setSuccess(false); + log.complain("Wrong value was returned by VirtualMachine.instanceCounts(" + className + "): " + instanceCounts + + ", expected: >= " + expectedValue); + } + } + } catch (Throwable e) { + setSuccess(false); + + log.complain("Unexpected exception when getting instance count info:"); + e.printStackTrace(log.getOutStream()); + } + } + + // Verifies number of instances of a class. + // Two types of checks are done: + // 1. Current instances >= old instances + created instances. + // 2. New instances >= created instances. + // + // The check in case 1 can only be done for classes where the test controls + // all created and deleted instances. + // Other classes, like java.lang.String, can not make this check since + // an instance in "old instances" may have been removed by a GC. + // In that case the tetst would fail because it finds too few current instances. + public void checkDebugeeAnswer_instanceCounts(String className, int countCreated, List oldReferences) { + if (strictCheck(className)) { + int countAll = countCreated + oldReferences.size(); + checkDebugeeAnswer_instanceCounts(className, countAll); + checkDebugeeAnswer_instances(className, countAll); + } else { + // isDebuggeeReady() check is hidden in checkDebugeeAnswer_instanceCounts() above. + // Must call it separately if we don't call checkDebugeeAnswer_instanceCounts(). + if (!isDebuggeeReady()) { + return; + } + } + + // Verify number of new instances created. + int countFoundCreated = countNewInstances(className, oldReferences); + if (countFoundCreated < countCreated) { + setSuccess(false); + log.complain("Too few new instances(" + className + "). Expected >= " + countCreated + ", found " + countFoundCreated); + } + } + + private int countNewInstances(String className, List oldReferences) { + // New references = current references - old references. + List newReferences = new ArrayList(getObjectReferences(className, vm)); + newReferences.removeAll(oldReferences); + return newReferences.size(); + } + + // check value returned by InterfaceType.instances + protected void checkDebugeeAnswer_InterfaceType_instances(InterfaceType interfaceType, int expectedInstances) { + int instanceCounts = interfaceType.instances(0).size(); + + if (instanceCounts != expectedInstances) { + setSuccess(false); + log.complain("List with wrong size was returned by InterfaceType.instances(" + interfaceType.name() + "): " + instanceCounts + + ", expected: " + expectedInstances); + } + } + + static public List filterObjectReferrence(List objectsToFilter, List sourceList) { + List result = new ArrayList(); + + for (ObjectReference object : sourceList) { + if (!objectsToFilter.contains(object)) + result.add(object); + } + + return result; + } + + static public List getObjectReferences(String className, VirtualMachine vm) { + List referenceTypes = vm.classesByName(className); + + List objectReferences; + + if (referenceTypes.size() == 0) + objectReferences = new ArrayList(); + else if (referenceTypes.size() == 1) + objectReferences = referenceTypes.get(0).instances(0); + else { + throw new TestBug("Unexpected collection size returned by VirtualMachine.classesByName: " + referenceTypes.size() + + ", only 1 entry was expected."); + } + + return objectReferences; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebuggee.java new file mode 100644 index 00000000000..ff808c7051a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebuggee.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.*; +import java.util.*; +import nsk.share.TestBug; + +/* + * Subclasses of this class generate events and if needed + * save debug information about generated events + */ +abstract class EventActionsExecutor { + // should this event generator save information about generated events + public boolean saveEventData; + + // information about generated events(this data available for debugger) + public List debugEventDataList = new ArrayList(); + + public abstract void doEventAction(); + + protected void addEventData(DebuggeeEventData.DebugEventData eventData) { + if (saveEventData) + debugEventDataList.add(eventData); + } + + public void clearDebugData() { + debugEventDataList.clear(); + } +} + +/* + * Class handles commands for running given number of threads which generate + * given events. Objects which generate events save information about generated + * events and this data available for debugger + * + * Class was written to test monitor evens(MonitorWaitEvent, MonitorWaitedEvent, + * MonitorContendedEnterEvent, MonitorContendedEnteredEvent), possible it can be + * used in tests for other events + */ +abstract public class JDIEventsDebuggee extends AbstractJDIDebuggee { + protected String[] doInit(String[] args) { + Thread.currentThread().setName(MAIN_THREAD_NAME); + return super.doInit(args); + } + + public static final String MAIN_THREAD_NAME = "JDIEventsDebuggee_MainThread"; + + // command:events_count:event types + public static final String COMMAND_CREATE_ACTIONS_EXECUTORS = "createActionsExecutors"; + + // command + public static final String COMMAND_START_EXECUTION = "startExecution"; + + // command + public static final String COMMAND_WAIT_EXECUTION_COMPLETION = "waitExecutionCompletion"; + + // command + public static final String COMMAND_STOP_EXECUTION = "stopExecution"; + + protected List eventActionsExecutorsPool = new ArrayList(); + + // initialize with empty array + public static DebuggeeEventData.DebugEventData generatedEvents[] = new DebuggeeEventData.DebugEventData[0]; + + // debuggee's main thread also can generate events and information about + // this events should be saved (like for event generators) + protected boolean saveEventData; + + public boolean parseCommand(String command) { + if (super.parseCommand(command)) + return true; + + StreamTokenizer tokenizer = new StreamTokenizer(new StringReader( + command)); + tokenizer.whitespaceChars(':', ':'); + tokenizer.wordChars('_', '_'); + tokenizer.wordChars(' ', ' '); + + try { + if (command.startsWith(COMMAND_CREATE_ACTIONS_EXECUTORS)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) + throw new TestBug("Invalid command format: " + command); + + int eventsCount = (int) tokenizer.nval; + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + // pass to the createActionsExecutors() string describing types + // of tested events + createActionsExecutors(tokenizer.sval, eventsCount); + + return true; + } else if (command.equals(COMMAND_START_EXECUTION)) { + startExecution(); + + return true; + } else if (command.equals(COMMAND_WAIT_EXECUTION_COMPLETION)) { + if (executionControllingThread == null) + throw new TestBug("executionControllingThread wasn't started"); + + try { + executionControllingThread.join(); + executionControllingThread = null; + } catch (InterruptedException e) { + unexpectedException(e); + } + + return true; + } else if (command.equals(COMMAND_STOP_EXECUTION)) { + if (executionControllingThread == null) + throw new TestBug("executionControllingThread wasn't started"); + + for (EventActionsThread thread : eventActionsExecutorsPool) { + thread.stopExecution(); + } + + return true; + } + + } catch (IOException e) { + throw new TestBug("Invalid command format: " + command); + } + + return false; + } + + // debugee waits completion of test threads in separate thread to free thread listening commands + protected Thread executionControllingThread; + + protected void startExecution() { + if (eventActionsExecutorsPool.size() == 0) { + throw new TestBug("ActionsExecutors were not created"); + } + + for (EventActionsThread thread : eventActionsExecutorsPool) { + thread.startExecution(); + } + + // debugee waits completion of test threads in separate thread to free thread listening commands + executionControllingThread = new Thread( + new Runnable() { + public void run() { + for (EventActionsThread thread : eventActionsExecutorsPool) { + try { + thread.join(); + } catch (InterruptedException e) { + unexpectedException(e); + } + } + + completeExecution(); + } + }); + + executionControllingThread.start(); + } + + protected void completeExecution() { + // save information about all generated events in array 'generatedEvents' + List generatedEventsList = new ArrayList(); + + for (EventActionsThread thread : eventActionsExecutorsPool) + generatedEventsList.addAll(thread.executor.debugEventDataList); + + generatedEvents = generatedEventsList.toArray(new DebuggeeEventData.DebugEventData[]{}); + + // stop at breakpoint when all events was generated + breakpointMethod(); + + // clear data about generated events to allow execute command + // several times + clearResults(); + } + + // clear data about generated events to allow execute test several times + protected void clearResults() { + for (EventActionsThread thread : eventActionsExecutorsPool) + thread.executor.clearDebugData(); + + eventActionsExecutorsPool.clear(); + + generatedEvents = new DebuggeeEventData.DebugEventData[0]; + } + + // create threads generating events + abstract protected void createActionsExecutors(String description, + int eventsCount); + + /* + * Thread generating events, call in loop + * EventActionsExecutor.doEventAction() + */ + static class EventActionsThread extends Thread { + // how many times call executor.doMonitorAction() + private int actionsNumber; + + // object generating events + public EventActionsExecutor executor; + + public EventActionsThread(EventActionsExecutor executor, + int actionsNumber) { + this.actionsNumber = actionsNumber; + this.executor = executor; + } + + private volatile boolean startExecution; + private volatile boolean stopExecution; + + public void run() { + while (!startExecution) + yield(); + + for (int i = 0; (i < actionsNumber) && !stopExecution; i++) + executor.doEventAction(); + } + + public void startExecution() { + startExecution = true; + } + + public void stopExecution() { + stopExecution = true; + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebugger.java new file mode 100644 index 00000000000..d63598b452c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebugger.java @@ -0,0 +1,909 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.PrintStream; +import java.lang.reflect.*; +import java.util.*; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; +import nsk.share.TestBug; + +/* + * Class is used as base debugger in tests for following events and event requests: + * - MonitorContendedEnterRequest / MonitorContendedEnterEvent + * - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent + * - MonitorWaitRequest / MonitorWaitEvent + * - MonitorWaitedRequest / MonitorWaitedEvent + * + * In all these tests similar scenario is used: + * - debugger VM forces debuggee VM to create number of objects which should generate events during test + * - if any event filters are used each generating event object is checked is this object accepted by all filters, + * if object was accepted it should save information about all generated events and this information is available for debugger + * - debuggee performs event generation and stop at breakpoint + * - debugger reads data saved by event generators and checks is only expected events was generated + */ +public class JDIEventsDebugger extends TestDebuggerType2 { + // types of tested events + static public enum EventType { + MONITOR_CONTENTED_ENTER, + MONITOR_CONTENTED_ENTERED, + MONITOR_WAIT, + MONITOR_WAITED + } + + /* + * Class contains information required for event testing + */ + static class TestedEventData { + // event class + public Class eventClass; + + // class representing event data on debuggee's side + public Class eventDataMirrorClass; + + // class representing event data on debugger's side + public Class eventDataClass; + + public TestedEventData(Class eventClass, Class eventDataMirrorClass, Class eventDataClass) { + this.eventClass = eventClass; + this.eventDataMirrorClass = eventDataMirrorClass; + this.eventDataClass = eventDataClass; + } + } + + static public Map testedEventData = new HashMap(); + + static { + testedEventData.put(EventType.MONITOR_CONTENTED_ENTER, new TestedEventData(MonitorContendedEnterEvent.class, + DebuggeeEventData.DebugMonitorEnterEventData.class, DebuggerEventData.DebugMonitorEnterEventData.class)); + + testedEventData.put(EventType.MONITOR_CONTENTED_ENTERED, new TestedEventData(MonitorContendedEnteredEvent.class, + DebuggeeEventData.DebugMonitorEnteredEventData.class, DebuggerEventData.DebugMonitorEnteredEventData.class)); + + testedEventData.put(EventType.MONITOR_WAIT, new TestedEventData(MonitorWaitEvent.class, DebuggeeEventData.DebugMonitorWaitEventData.class, + DebuggerEventData.DebugMonitorWaitEventData.class)); + + testedEventData.put(EventType.MONITOR_WAITED, new TestedEventData(MonitorWaitedEvent.class, + DebuggeeEventData.DebugMonitorWaitedEventData.class, DebuggerEventData.DebugMonitorWaitedEventData.class)); + } + + static public TestedEventData[] eventDataByEventTypes(EventType[] eventTypes) { + TestedEventData[] result = new TestedEventData[eventTypes.length]; + + int i = 0; + for (EventType eventType : eventTypes) { + TestedEventData eventData = testedEventData.get(eventType); + + if (eventData == null) + throw new TestBug("Unsupported event type: " + eventType); + + result[i++] = eventData; + } + + return result; + } + + /* + * Dummy event listener, just accepts all events + */ + public class DummyEventListener extends EventHandler.EventListener { + private volatile boolean breakpointEventReceived; + + public boolean eventReceived(Event event) { + if (event instanceof BreakpointEvent) { + breakpointEventReceived = true; + vm.resume(); + } + + return true; + } + + public void waitBreakpoint() { + while (!breakpointEventReceived) + Thread.yield(); + } + } + + /* + * Parse common for event tests parameters + */ + protected String[] doInit(String[] args, PrintStream out) { + args = super.doInit(args, out); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-allowExtraEvents")) { + extraEventClasses = createEventClassArray(args[i + 1]); + + i++; + } else if (args[i].equals("-allowMissedEvents")) { + missedEventClasses = createEventClassArray(args[i + 1]); + + i++; + } else + standardArgs.add(args[i]); + } + + return standardArgs.toArray(new String[standardArgs.size()]); + } + + // can't control some kinds of events (events from system libraries) and + // not all events should be saved for analysis + // (should be implemented in subclasses) + protected boolean shouldSaveEvent(Event event) { + return true; + } + + public Class findEventDataClass(TestedEventData[] testedEventData, Event event) { + for (TestedEventData eventData : testedEventData) { + if (eventData.eventClass.isAssignableFrom(event.getClass())) + return eventData.eventClass; + } + + return null; + } + + /* + * This event listener stores received monitor events until BreakpointEvent + * is not received, after getting of BreakpointEvent checks only expected + * events were received + */ + public class EventListener extends EventHandler.EventListener { + + private TestedEventData[] testedEventData; + + public EventListener(TestedEventData[] testedEventData) { + this.testedEventData = testedEventData; + } + + private boolean shouldHandleEvent(Event event) { + return findEventDataClass(testedEventData, event) == null ? false : true; + } + + volatile boolean breakpointWasReceived; + + // execution was interrupted because of timeout + volatile boolean executionWasInterrupted; + + public boolean eventReceived(Event event) { + if (shouldHandleEvent(event)) { + if (shouldSaveEvent(event)) { + + Class eventClass; + + eventClass = findEventDataClass(testedEventData, event); + List events = allReceivedEvents.get(eventClass); + + if (events == null) { + events = new LinkedList(); + allReceivedEvents.put(eventClass, events); + } + + events.add(event); + } + + return true; + } + // debuggee should stop at the end of test + else if (event instanceof BreakpointEvent) { + breakpointWasReceived = true; + + try { + // if execution was interrupted because of timeout don't check received + // events because it can consume too much time + if (!executionWasInterrupted) { + // get data from debuggee about all generated events + initExpectedEvents(testedEventData); + + checkEvents(); + } else + log.complain("WARNING: execution was interrupted because of timeout, test doesn't check received events"); + } catch (Throwable t) { + unexpectedException(t); + } + + vm.resume(); + + return true; + } + + return false; + } + } + + protected Class extraEventClasses[]; + + protected Class missedEventClasses[]; + + /* + * If test can't strictly control event generation it may allow generation + * of extra events and unexpected events aren't treated as error + * (subclasses should specify what kinds of extra events are allowed) + */ + private Class[] allowedExtraEvents() { + return extraEventClasses; + } + + /* + * If test can't strictly control event generation case when debugger doesn't + * receive expected event may be not treated as failure + * (subclasses should specify what kinds of expected events can be not received) + */ + private Class[] allowedMissedEvents() { + return missedEventClasses; + } + + private boolean isExtraEventAllowed(Class eventClass) { + return checkEvent(eventClass, allowedExtraEvents()); + } + + private boolean isMissedEventAllowed(Class eventClass) { + return checkEvent(eventClass, allowedMissedEvents()); + } + + private boolean checkEvent(Class eventClass, Class classes[]) { + if (classes == null) + return false; + + for (Class klass : classes) { + if (klass.isAssignableFrom(eventClass)) + return true; + } + + return false; + } + + // flag is modified from the event listener thread + private volatile boolean eventsNotGenerated; + + /* + * Method returns true if test expects event generation, but events weren't + * generated. If test can't strictly control event generation such case isn't + * necessarily treated as test failure (sublasses of JDIEventsDebugger can + * for example try to rerun test several times). + */ + protected boolean eventsNotGenerated() { + return eventsNotGenerated; + } + + /* + * Print debug information about expected and received events(this data + * should be stored in lists 'allExpectedEvents' and 'allReceivedEvents') + * and check that only expected events were received + */ + private void checkEvents() { + if (getAllExpectedEvents().size() > 0 && getAllReceivedEvents().size() == 0 && allowedMissedEvents() != null) { + log.display("WARNING: didn't receive any event"); + eventsNotGenerated = true; + } + + log.display("ALL RECEIVED EVENTS: "); + for (Event event : getAllReceivedEvents()) + log.display("received event: " + eventToString(event)); + + log.display("ALL EXPECTED EVENTS: "); + for (DebuggerEventData.DebugEventData eventData : getAllExpectedEvents()) + log.display("expected event: " + eventData); + + // try to find received event in the list of expected events, if this event + // was found remove data about events from both lists + for (Class eventClass : allReceivedEvents.keySet()) { + List receivedEvents = allReceivedEvents.get(eventClass); + List expectedEvents = allExpectedEvents.get(eventClass); + + for (Iterator allReceivedEventsIterator = receivedEvents.iterator(); + allReceivedEventsIterator.hasNext();) { + + Event event = allReceivedEventsIterator.next(); + + for (Iterator allExpectedEventsIterator = expectedEvents.iterator(); + allExpectedEventsIterator.hasNext();) { + + DebuggerEventData.DebugEventData debugEventData = allExpectedEventsIterator.next(); + + if (debugEventData.shouldCheckEvent(event)) { + if (debugEventData.checkEvent(event)) { + allExpectedEventsIterator.remove(); + allReceivedEventsIterator.remove(); + break; + } + } + } + } + } + + List receivedEventsLeft = getAllReceivedEvents(); + + // check is all received events were found in expected + if (receivedEventsLeft.size() > 0) { + // if allowExtraEvents = true extra events are not treated as error + for (Event event : receivedEventsLeft) { + if (!isExtraEventAllowed(event.getClass())) { + setSuccess(false); + log.complain("Unexpected event " + eventToString(event)); + } + } + } + + List expectedEventsLeft = getAllExpectedEvents(); + + // check is all expected events were received + if (expectedEventsLeft.size() > 0) { + for (DebuggerEventData.DebugEventData eventData : expectedEventsLeft) { + if (!isMissedEventAllowed(eventData.eventClass)) { + setSuccess(false); + log.complain("Expected event was not generated: " + eventData); + } + } + } + } + + private String eventToString(Event event) { + try { + if (event instanceof MonitorContendedEnterEvent) + return event + ". Details(MonitorContendedEnterEvent):" + " Monitor: " + ((MonitorContendedEnterEvent) event).monitor() + " Thread: " + + ((MonitorContendedEnterEvent) event).thread(); + else if (event instanceof MonitorContendedEnteredEvent) + return event + ". Details(MonitorContendedEnteredEvent):" + " Monitor: " + ((MonitorContendedEnteredEvent) event).monitor() + + " Thread: " + ((MonitorContendedEnteredEvent) event).thread(); + else if (event instanceof MonitorWaitEvent) + return event + ". Details(MonitorWaitEvent):" + " Monitor: " + ((MonitorWaitEvent) event).monitor() + " Thread: " + + ((MonitorWaitEvent) event).thread() + " Timeout: " + ((MonitorWaitEvent) event).timeout(); + else if (event instanceof MonitorWaitedEvent) + return event + ". Details(MonitorWaitedEvent):" + " Monitor: " + ((MonitorWaitedEvent) event).monitor() + " Thread: " + + ((MonitorWaitedEvent) event).thread() + " Timedout: " + ((MonitorWaitedEvent) event).timedout(); + + return event.toString(); + } + // this exception can occur when unexpected event was received + catch (ObjectCollectedException e) { + // allowExtraEvents=true extra events are not treated as error + if (!isExtraEventAllowed(event.getClass())) { + setSuccess(false); + e.printStackTrace(log.getOutStream()); + log.complain("Unexpected ObjectCollectedException was caught, possible unexpected event was received"); + } + + return event.getClass().getName() + " [ Can't get full description, ObjectCollectedException was thrown ]"; + } + } + + // events received during test execution are stored here + private Map, List> allReceivedEvents = new HashMap, List>(); + + private List getAllReceivedEvents() { + List result = new LinkedList(); + + for (Class eventClass : allReceivedEvents.keySet()) { + result.addAll(allReceivedEvents.get(eventClass)); + } + + return result; + } + + protected Map, List> allExpectedEvents = new HashMap, List>(); + + private List getAllExpectedEvents() { + List result = new LinkedList(); + + for (Class eventClass : allExpectedEvents.keySet()) { + result.addAll(allExpectedEvents.get(eventClass)); + } + + return result; + } + + // find in debuggee VM and add to the list 'allExpectedEvents' instances + // of classes representing generated events + protected void initExpectedEvents(TestedEventData testedEventData[]) { + List events; + + ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs()); + + ArrayReference generatedEvents = (ArrayReference) referenceType.getValue(referenceType.fieldByName("generatedEvents")); + + for (TestedEventData eventData : testedEventData) { + events = new LinkedList(); + allExpectedEvents.put(eventData.eventClass, events); + } + + for (int i = 0; i < generatedEvents.length(); i++) { + ObjectReference debuggeeMirror = (ObjectReference) generatedEvents.getValue(i); + + for (TestedEventData eventData : testedEventData) { + + if (debuggeeMirror.referenceType().name().equals(eventData.eventDataMirrorClass.getName())) { + events = allExpectedEvents.get(eventData.eventClass); + + /* + * Use reflection to create object representing generated + * event Event data class should has constructor with single + * parameter of type com.sun.jdi.ObjectReference + */ + Constructor constructor; + + try { + constructor = eventData.eventDataClass.getConstructor(new Class[] { ObjectReference.class }); + } catch (NoSuchMethodException e) { + TestBug testBug = new TestBug( + "Class representing debug event data should implement constructor with single parameter of type com.sun.jdi.ObjectReference"); + testBug.initCause(e); + throw testBug; + } + + DebuggerEventData.DebugEventData expectedEvent; + + try { + expectedEvent = (DebuggerEventData.DebugEventData) constructor.newInstance(new Object[] { debuggeeMirror }); + } catch (Exception e) { + TestBug testBug = new TestBug("Error when create debug event data: " + e); + testBug.initCause(e); + throw testBug; + } + events.add(expectedEvent); + } + } + } + } + + private void printFiltersInfo() { + if (eventFilters.size() > 0) { + log.display("Use following filters: "); + + for (EventFilters.DebugEventFilter filter : eventFilters) + log.display("" + filter); + } else { + log.display("Don't use event filters"); + } + } + + // filters used in test + protected List eventFilters = new LinkedList(); + + // Check is object generating events matches all filters, + // if object was accepted by all filters set this object's field + // 'saveEventData' to 'true', otherwise to 'false', + private void checkEventGenerator(ThreadReference eventThread, ObjectReference executor) { + boolean acceptedByFilters = true; + + for (EventFilters.DebugEventFilter eventFilter : eventFilters) { + if (!eventFilter.isObjectMatch(executor, eventThread)) { + acceptedByFilters = false; + break; + } + } + + try { + executor.setValue(executor.referenceType().fieldByName("saveEventData"), vm.mirrorOf(acceptedByFilters)); + } catch (Exception e) { + throw new TestBug("Unexpected exception when change object field in debugee VM: " + e, e); + } + } + + /* + * Find all event generating threads in debuggee VM (instances of + * nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread) all these + * threads have special field - 'executor', this is object which generates + * events. If event generating thread and event generating object was + * accepted by all filters generating object should store information about + * all generated events and this information will be available for debugger + */ + protected void initializeEventGenerators() { + printFiltersInfo(); + + List eventThreads = getEventThreads(); + + for (ThreadReference eventThread : eventThreads) { + ObjectReference executor = (ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor")); + checkEventGenerator(eventThread, executor); + } + + // debuggee's main thread also can generate events, need to filter it in + // the same way as other threads + checkEventGenerator(debuggee.threadByName(JDIEventsDebuggee.MAIN_THREAD_NAME), findSingleObjectReference(debuggeeClassNameWithoutArgs())); + } + + // find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread + protected List getEventThreads() { + ReferenceType referenceType = debuggee.classByName(JDIEventsDebuggee.EventActionsThread.class.getName()); + List debuggeeEventThreads = referenceType.instances(0); + + List result = new LinkedList(); + for (ObjectReference threadReference : debuggeeEventThreads) + result.add((ThreadReference) threadReference); + + return result; + } + + // find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread, + // and get value of this object's field with name 'executor' + protected List getEventObjects() { + List eventObjects = new LinkedList(); + + List eventThreads = getEventThreads(); + + for (ThreadReference eventThread : eventThreads) { + eventObjects.add((ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor"))); + } + + return eventObjects; + } + + // remove all filters, received and expected events + private void clearTestData() { + allExpectedEvents.clear(); + allReceivedEvents.clear(); + eventFilters.clear(); + eventsNotGenerated = false; + } + + private boolean isEventSupported(EventType eventType) { + switch (eventType) { + case MONITOR_CONTENTED_ENTER: + case MONITOR_CONTENTED_ENTERED: + case MONITOR_WAIT: + case MONITOR_WAITED: + return vm.canRequestMonitorEvents(); + + default: + throw new TestBug("Invalid tested event type: " + eventType); + } + } + + // create instance of EventRequest depending on given eventType + private EventRequest createTestRequest(EventType eventType) { + switch (eventType) { + case MONITOR_CONTENTED_ENTER: + return debuggee.getEventRequestManager().createMonitorContendedEnterRequest(); + case MONITOR_CONTENTED_ENTERED: + return debuggee.getEventRequestManager().createMonitorContendedEnteredRequest(); + case MONITOR_WAIT: + return debuggee.getEventRequestManager().createMonitorWaitRequest(); + case MONITOR_WAITED: + return debuggee.getEventRequestManager().createMonitorWaitedRequest(); + + default: + throw new TestBug("Invalid tested event type: " + eventType); + } + } + + // create command depending on given eventType + private String createCommand(EventType eventTypes[], int eventsNumber) { + String command = JDIEventsDebuggee.COMMAND_CREATE_ACTIONS_EXECUTORS + ":" + eventsNumber + ":"; + + for (EventType eventType : eventTypes) { + switch (eventType) { + case MONITOR_CONTENTED_ENTER: + case MONITOR_CONTENTED_ENTERED: + case MONITOR_WAIT: + case MONITOR_WAITED: + command += " " + eventType.name(); + break; + + default: + throw new TestBug("Invalid tested event type: " + eventType); + } + } + + return command; + } + + // get list of event requests from EventRequestManager depending on the given eventType + private List getEventRequestsFromManager(EventType eventType) { + switch (eventType) { + case MONITOR_CONTENTED_ENTER: + return debuggee.getEventRequestManager().monitorContendedEnterRequests(); + case MONITOR_CONTENTED_ENTERED: + return debuggee.getEventRequestManager().monitorContendedEnteredRequests(); + case MONITOR_WAIT: + return debuggee.getEventRequestManager().monitorWaitRequests(); + case MONITOR_WAITED: + return debuggee.getEventRequestManager().monitorWaitedRequests(); + + default: + throw new TestBug("Invalid tested event type: " + eventType); + } + } + + protected EventHandler eventHandler; + + private EventListener eventListener; + + // perform event generation before test begins to load all using classes + // and avoid unexpected events related to classloading + protected void prepareDebuggee(EventType[] eventTypes) { + initDefaultBreakpoint(); + + eventHandler = new EventHandler(debuggee, log); + eventHandler.startListening(); + + // use event listener which just skip all received events + DummyEventListener dummyEventListener = new DummyEventListener(); + eventHandler.addListener(dummyEventListener); + + EventRequest eventRequests[] = new EventRequest[eventTypes.length]; + + for (int i = 0; i < eventRequests.length; i++) { + eventRequests[i] = createTestRequest(eventTypes[i]); + eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE); + eventRequests[i].enable(); + } + + // debuggee should create event generators + pipe.println(createCommand(eventTypes, 1)); + + if (!isDebuggeeReady()) + return; + + // start event generation + pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION); + + if (!isDebuggeeReady()) + return; + + for (int i = 0; i < eventRequests.length; i++) + eventRequests[i].disable(); + + dummyEventListener.waitBreakpoint(); + + eventHandler.removeListener(dummyEventListener); + + pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION); + + if (!isDebuggeeReady()) + return; + + eventListener = new EventListener(eventDataByEventTypes(eventTypes)); + eventHandler.addListener(eventListener); + } + + /* + * Method for stress testing, allows specify requests for several event + * types, number of events which should be generated during test and number + * of threads which simultaneously generate events + */ + protected void stressTestTemplate(EventType[] eventTypes, int eventsNumber, int threadsNumber) { + for (EventType eventType : eventTypes) { + if (!isEventSupported(eventType)) { + log.complain("Can't test event because of it isn't supported: " + eventType); + return; + } + } + + // Used framework is intended for testing event filters and debuggee + // creates 3 threads performing event generation and there is possibility + // to filter events from some threads + for (int i = 0; i < threadsNumber; i++) { + pipe.println(createCommand(eventTypes, eventsNumber)); + + if (!isDebuggeeReady()) + return; + } + + // clear data(if this method is executed several times) + clearTestData(); + + initializeEventGenerators(); + + EventRequest eventRequests[] = new EventRequest[eventTypes.length]; + + // create event requests + for (int i = 0; i < eventTypes.length; i++) { + eventRequests[i] = createTestRequest(eventTypes[i]); + eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE); + eventRequests[i].enable(); + + log.display("Use following event request: " + eventRequests[i]); + } + + // stressTestTemplate can control only execution time, so ignore iteration count + stresser.start(0); + try { + // start event generation + pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION); + + if (!isDebuggeeReady()) + return; + + // check is stressTime exceeded + while (stresser.continueExecution()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + unexpectedException(e); + } + + // periodically check is test completed + if (eventListener.breakpointWasReceived) + break; + } + } finally { + stresser.finish(); + } + + // debugger should interrupt test because of timeout + if (!eventListener.breakpointWasReceived) { + + eventListener.executionWasInterrupted = true; + + log.complain("WARNING: time is exceeded, interrupt test"); + + pipe.println(JDIEventsDebuggee.COMMAND_STOP_EXECUTION); + + if (!isDebuggeeReady()) + return; + } + + pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION); + + if (!isDebuggeeReady()) + return; + + for (int i = 0; i < eventRequests.length; i++) + eventRequests[i].disable(); + } + + /* + * Hook method for subclasses implementing tests against event filters (it is called from eventFilterTestTemplate) + */ + protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) { + throw new TestBug("Not implemented"); + } + + /* + * Test event request with filter + * + * Also this method check following: + * - InvalidRequestStateException is thrown if add filter for deleted or enabled request + * - EventRequestManager.xxxRequests() returns created event request + */ + protected void eventFilterTestTemplate(EventType eventType, int testedFilterIndex) { + if (!isEventSupported(eventType)) { + log.complain("Can't test event because of it isn't supported: " + eventType); + return; + } + + // debuggee create event generators + pipe.println(createCommand(new EventType[] { eventType }, 1)); + + if (!isDebuggeeReady()) + return; + + clearTestData(); + + EventFilters.DebugEventFilter[] filters = createTestFilters(testedFilterIndex); + + for (EventFilters.DebugEventFilter filter : filters) { + if (filter.isSupported(vm)) + eventFilters.add(filter); + else { + log.complain("Can't test filter because of it isn't supported: " + filter); + return; + } + } + + initializeEventGenerators(); + + // create event request + EventRequest request = createTestRequest(eventType); + request.setSuspendPolicy(EventRequest.SUSPEND_NONE); + + // try add filter to enabled request, expect + // 'InvalidRequestStateException' + request.enable(); + try { + for (EventFilters.DebugEventFilter filter : filters) + filter.addFilter(request); + + setSuccess(false); + log.complain("Expected 'InvalidRequestStateException' was not thrown"); + } catch (InvalidRequestStateException e) { + // expected exception + } catch (Throwable e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + + // add event filter + request.disable(); + + for (EventFilters.DebugEventFilter filter : filters) + addFilter(filter, request); + + request.enable(); + + log.display("Use following event request: " + request); + + // start event generation + pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION); + + if (!isDebuggeeReady()) + return; + + // wait execution completion + pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION); + + if (!isDebuggeeReady()) + return; + + // check that method EventRequestManager.xxxRequests() return created + // request + if (!getEventRequestsFromManager(eventType).contains(request)) { + setSuccess(false); + log.complain("EventRequestManager doesn't return request: " + request); + } + + // delete event request + debuggee.getEventRequestManager().deleteEventRequest(request); + + // try add filter to removed request, expect + // 'InvalidRequestStateException' + try { + for (EventFilters.DebugEventFilter filter : filters) + filter.addFilter(request); + setSuccess(false); + log.complain("Expected 'InvalidRequestStateException' was not thrown"); + } catch (InvalidRequestStateException e) { + // expected exception + } catch (Throwable t) { + unexpectedException(t); + } + } + + private void addFilter(EventFilters.DebugEventFilter filter, EventRequest request) { + try { + filter.addFilter(request); + } catch (Throwable t) { + unexpectedException(t); + } + } + + // used to parse parameters -allowExtraEvents and -allowMissedEvents + private Class[] createEventClassArray(String string) { + String eventTypesNames[] = string.split(":"); + EventType eventTypes[] = new EventType[eventTypesNames.length]; + try { + for (int i = 0; i < eventTypesNames.length; i++) { + eventTypes[i] = EventType.valueOf(eventTypesNames[i]); + } + } catch (IllegalArgumentException e) { + throw new TestBug("Invalid event type", e); + } + + if (eventTypesNames.length == 0) + throw new TestBug("Event types weren't specified"); + + Class[] result = new Class[eventTypesNames.length]; + + for (int i = 0; i < result.length; i++) + result[i] = testedEventData.get(eventTypes[i]).eventClass; + + return result; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MockReferenceType.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MockReferenceType.java new file mode 100644 index 00000000000..aaf172326c6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MockReferenceType.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import com.sun.jdi.*; + +import java.util.List; +import java.util.Map; + +/** + * A mock implementation of com.sun.jdi.ReferenceType interface. + */ + +public class MockReferenceType implements ReferenceType { + + private final String signature; + private final String name; + private final VirtualMachine virtualMachine; + + private MockReferenceType(VirtualMachine virtualMachine, String signature, String name) { + this.signature = signature; + this.name = name; + this.virtualMachine = virtualMachine; + } + + @Override + public String signature() { + return signature; + } + + @Override + public String name() { + return name; + } + + @Override + public String genericSignature() { + return null; + } + + @Override + public ClassLoaderReference classLoader() { + return null; + } + + @Override + public String sourceName() throws AbsentInformationException { + return null; + } + + @Override + public List sourceNames(String stratum) throws AbsentInformationException { + return null; + } + + @Override + public List sourcePaths(String stratum) throws AbsentInformationException { + return null; + } + + @Override + public String sourceDebugExtension() throws AbsentInformationException { + return null; + } + + @Override + public boolean isStatic() { + return false; + } + + @Override + public boolean isAbstract() { + return false; + } + + @Override + public boolean isFinal() { + return false; + } + + @Override + public boolean isPrepared() { + return false; + } + + @Override + public boolean isVerified() { + return false; + } + + @Override + public boolean isInitialized() { + return false; + } + + @Override + public boolean failedToInitialize() { + return false; + } + + @Override + public List fields() { + return null; + } + + @Override + public List visibleFields() { + return null; + } + + @Override + public List allFields() { + return null; + } + + @Override + public Field fieldByName(String fieldName) { + return null; + } + + @Override + public List methods() { + return null; + } + + @Override + public List visibleMethods() { + return null; + } + + @Override + public List allMethods() { + return null; + } + + @Override + public List methodsByName(String name) { + return null; + } + + @Override + public List methodsByName(String name, String signature) { + return null; + } + + @Override + public List nestedTypes() { + return null; + } + + @Override + public Value getValue(Field field) { + return null; + } + + @Override + public Map getValues(List fields) { + return null; + } + + @Override + public ClassObjectReference classObject() { + return null; + } + + @Override + public List allLineLocations() throws AbsentInformationException { + return null; + } + + @Override + public List allLineLocations(String stratum, String sourceName) throws AbsentInformationException { + return null; + } + + @Override + public List locationsOfLine(int lineNumber) throws AbsentInformationException { + return null; + } + + @Override + public List locationsOfLine(String stratum, String sourceName, int lineNumber) + throws AbsentInformationException { + return null; + } + + @Override + public List availableStrata() { + return null; + } + + @Override + public String defaultStratum() { + return null; + } + + @Override + public List instances(long maxInstances) { + return null; + } + + @Override + public int majorVersion() { + return 0; + } + + @Override + public int minorVersion() { + return 0; + } + + @Override + public int constantPoolCount() { + return 0; + } + + @Override + public byte[] constantPool() { + return new byte[0]; + } + + @Override + public VirtualMachine virtualMachine() { + return virtualMachine; + } + + @Override + public int modifiers() { + return 0; + } + + @Override + public boolean isPrivate() { + return false; + } + + @Override + public boolean isPackagePrivate() { + return false; + } + + @Override + public boolean isProtected() { + return false; + } + + @Override + public boolean isPublic() { + return false; + } + + @Override + public int compareTo(ReferenceType o) { + return 0; + } + + /* + * Creates a mock instance of com.sun.tools.jdi.ObjectReference with a given type. + */ + + public static Value createObjectReference(VirtualMachine virtualMachine, String typeSignature, String typeName) + throws Exception { + + Class clazz = Class.forName("com.sun.tools.jdi.ObjectReferenceImpl"); + java.lang.reflect.Constructor c = clazz.getDeclaredConstructor(VirtualMachine.class, long.class); + c.setAccessible(true); + Value objRef = (Value) c.newInstance(virtualMachine, 0); + + Type mockType = new MockReferenceType(virtualMachine, typeSignature, typeName); + java.lang.reflect.Field typeField = clazz.getDeclaredField("type"); + typeField.setAccessible(true); + typeField.set(objRef, mockType); + + return objRef; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEnterExecutor.c b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEnterExecutor.c new file mode 100644 index 00000000000..228a7c0ae6c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEnterExecutor.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "jni.h" +#include "nsk_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_PTR + +#ifdef __cplusplus +#define JNI_ENV_ARG_2(x, y) y +#define JNI_ENV_ARG_3(x,y, z) y, z +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG_2(x,y) x, y +#define JNI_ENV_ARG_3(x,y, z) x, y, z +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + +JNIEXPORT void JNICALL +Java_nsk_share_jdi_MonitorEnterExecutor_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject) +{ + jint success; + + success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero")); + } + + success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero")); + } +} + +JNIEXPORT void JNICALL +Java_nsk_share_jdi_MonitorEnterExecutor_11Subclass_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject) +{ + jint success; + + success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero")); + } + + success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero")); + } +} + +JNIEXPORT void JNICALL +Java_nsk_share_jdi_MonitorEnterExecutor_12Subclass_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject) +{ + jint success; + + success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero")); + } + + success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero")); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEventsDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEventsDebuggee.java new file mode 100644 index 00000000000..f412a26b3fb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEventsDebuggee.java @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.util.*; +import nsk.share.TestBug; +import nsk.share.locks.MonitorLockingThread; + +/* + * This class generates MonitorWaitEvent and MonitorWaitedEvent + */ +class MonitorWaitExecutor extends EventActionsExecutor { + // MonitorWaited event may occurs when waiting thread was interrupted, + // notified by notify or notifyAll, or when timeout expired + enum ExitFromWaitType { + EXIT_WITH_TIMEOUT, + INTERRUPT, + NOTIFY, + NOTIFY_ALL + } + + // this thread forces MonitorWaitExecutor to exit from wait() + class AuxiliaryThread extends Thread { + private Thread threadToInterrupt; + + private Object monitor; + + public AuxiliaryThread(Thread threadToInterrupt, Object monitor) { + this.threadToInterrupt = threadToInterrupt; + this.monitor = monitor; + } + + public void run() { + // wait when interrupted thread switches state to 'TIMED_WAITING' + while ((threadToInterrupt.getState() != Thread.State.WAITING) && !exitedFromWait) { + yield(); + } + + // threadToInterrupt 'spuriously' exited from wait() + if(exitedFromWait) + return; + + if (exitFromWaitType == ExitFromWaitType.INTERRUPT) { + threadToInterrupt.interrupt(); + } else if ((exitFromWaitType == ExitFromWaitType.NOTIFY) + || (exitFromWaitType == ExitFromWaitType.NOTIFY_ALL)) { + /* + * NOTE: thread's state WAITING doesn't guarantee that thread released + * monitor, and entering to the next synchronized block may cause MonitorContentedEnterEvent + * (if corresponding request was created). + * + * Debugger should take in account this issue. + */ + synchronized (monitor) { + if (exitFromWaitType == ExitFromWaitType.NOTIFY) + monitor.notify(); + else if (exitFromWaitType == ExitFromWaitType.NOTIFY_ALL) + monitor.notifyAll(); + } + } + } + } + + // thread may 'spuriously' exit from wait(), in this case AuxiliaryThread shouldn't wait 'WAITING' state + private volatile boolean exitedFromWait; + + // save data about MonitorWait events + private boolean monitorWait; + + // save data about MonitorWaited events + private boolean monitorWaited; + + public MonitorWaitExecutor(boolean monitorWait, boolean monitorWaited) { + this.monitorWait = monitorWait; + this.monitorWaited = monitorWaited; + } + + protected ExitFromWaitType exitFromWaitType; + + public void doEventAction() { + for (ExitFromWaitType exitType : ExitFromWaitType.values()) { + exitFromWaitType = exitType; + + monitorWait(); + } + } + + protected void monitorWait() { + + exitedFromWait = false; + + long timeout; + + if (exitFromWaitType == ExitFromWaitType.EXIT_WITH_TIMEOUT) + timeout = 100; + else + timeout = 0; + + if (monitorWait) { + DebuggeeEventData.DebugMonitorWaitEventData eventData = new DebuggeeEventData.DebugMonitorWaitEventData( + this, Thread.currentThread(), timeout, this); + addEventData(eventData); + } + + if (monitorWaited) { + DebuggeeEventData.DebugMonitorWaitedEventData eventData = new DebuggeeEventData.DebugMonitorWaitedEventData( + this, Thread.currentThread(), + (exitFromWaitType == ExitFromWaitType.EXIT_WITH_TIMEOUT), + this); + addEventData(eventData); + } + + AuxiliaryThread auxiliaryThread = null; + + if (exitFromWaitType != ExitFromWaitType.EXIT_WITH_TIMEOUT) { + auxiliaryThread = new AuxiliaryThread(Thread.currentThread(), this); + auxiliaryThread.start(); + } + + try { + eventMethod(timeout); + } catch (InterruptedException e) { + // expected exception + } + + exitedFromWait = true; + + if (auxiliaryThread != null) { + // don't using join, because of join is realized with using of + // wait(), and this method can generate unexpected events + while (auxiliaryThread.getState() != Thread.State.TERMINATED) + Thread.yield(); + } + } + + // move event actions to the separate method to simplify method redifinition + // in subclasses + synchronized protected void eventMethod(long timeout) + throws InterruptedException { + wait(timeout); + } + +} + +/* + * Subclass of MonitorWaitExecutor, define its own event method(copy of parent + * method), intended for event filters test + */ +class MonitorWaitExecutor_1Subclass extends MonitorWaitExecutor { + public MonitorWaitExecutor_1Subclass(boolean monitorWait, + boolean monitorWaited) { + super(monitorWait, monitorWaited); + } + + synchronized protected void eventMethod(long timeout) + throws InterruptedException { + wait(timeout); + } +} + +/* + * Subclass of MonitorWaitExecutor, define its own event method(copy of parent + * method), intended for event filters test + */ +class MonitorWaitExecutor_2Subclass extends MonitorWaitExecutor_1Subclass { + public MonitorWaitExecutor_2Subclass(boolean monitorWait, + boolean monitorWaited) { + super(monitorWait, monitorWaited); + } + + synchronized protected void eventMethod(long timeout) + throws InterruptedException { + wait(timeout); + } +} + +/* + * This class generates MonitorContendedEnterEvent and + * MonitorContendedEnteredEvent + */ +class MonitorEnterExecutor extends EventActionsExecutor { + /* + * Types of monitor acquiring: + * - through synchronized block + * - through synchronized method + * - through JNI MonitorEnter + */ + static enum MonitorAcquireType { + SYNCHRONIZED_BLOCK, + SYNCHRONIZED_METHOD, + JNI_MONITOR_ENTER + } + + // native method uses this class + private static final Class jniError = nsk.share.TestJNIError.class; + + + static final String nativeLibararyName = "MonitorEnterExecutor"; + + static { + System.loadLibrary(nativeLibararyName); + } + + // this thread forces MonitorLockingThread to release holding lock + static class LockFreeThread extends Thread { + private Thread blockedThread; + + private MonitorLockingThread lockingThread; + + public LockFreeThread(Thread blockedThread, + MonitorLockingThread lockingThread) { + this.blockedThread = blockedThread; + this.lockingThread = lockingThread; + } + + public void run() { + // wait when blocked thread switches state to 'BLOCKED' + while (blockedThread.getState() != Thread.State.BLOCKED) + yield(); + + lockingThread.releaseLock(); + } + } + + private boolean monitorEnter; + + private boolean monitorEntered; + + public MonitorEnterExecutor(boolean monitorEnter, boolean monitorEntered) { + this.monitorEnter = monitorEnter; + this.monitorEntered = monitorEntered; + } + + protected void monitorEnter() { + // locking thread acquires 'this' lock + MonitorLockingThread lockingThread = new MonitorLockingThread(this); + lockingThread.acquireLock(); + + if (monitorEnter) { + DebuggeeEventData.DebugMonitorEnterEventData eventData = new DebuggeeEventData.DebugMonitorEnterEventData( + this, Thread.currentThread(), this); + addEventData(eventData); + } + if (monitorEntered) { + DebuggeeEventData.DebugMonitorEnteredEventData eventData = new DebuggeeEventData.DebugMonitorEnteredEventData( + this, Thread.currentThread(), this); + addEventData(eventData); + } + + /* + * This thread forces lockingThread to free 'this' lock when current thread's state will change to 'BLOCKED' + * + * NOTE: this method to provoke MonitorContended events isn't 100% robust + * Tests should take in account this issue. + * + */ + LockFreeThread lockFreeThread = new LockFreeThread(Thread.currentThread(), lockingThread); + lockFreeThread.start(); + + // try to acquire 'this' lock + eventMethod(); + + while(lockingThread.getState() != Thread.State.TERMINATED) + Thread.yield(); + + while(lockFreeThread.getState() != Thread.State.TERMINATED) + Thread.yield(); + } + + private MonitorAcquireType monitorAcquireType; + + // generate events in different ways + public void doEventAction() { + for (MonitorAcquireType monitorAcquireType : MonitorAcquireType.values()) { + this.monitorAcquireType = monitorAcquireType; + monitorEnter(); + } + } + + protected void eventMethod() { + switch (monitorAcquireType) { + case SYNCHRONIZED_BLOCK: + synchronizedBlock(); + break; + case SYNCHRONIZED_METHOD: + synchronizedMethod(); + break; + case JNI_MONITOR_ENTER: + nativeJNIMonitorEnter(); + break; + + default: + throw new TestBug("Invalid monitorAcquireType: " + + monitorAcquireType); + } + } + + // move event actions to the separate methods to simplify method + // redifinition in subclasses: + + protected void synchronizedBlock() { + // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here + synchronized (this) { + // don't expect events for following synchronized block + synchronized (this) { + } + } + } + + // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here + synchronized protected void synchronizedMethod() { + // don't expect events for following synchronized block + synchronized (this) { + } + } + + // call JNI methods MonitorEnter and MonitorExit for 'this' object + protected native void nativeJNIMonitorEnter(); + +} + +/* + * Subclass of MonitorEnterExecutor, defines its own event methods(copy of parent + * method), intended for event filters test + */ +class MonitorEnterExecutor_1Subclass extends MonitorEnterExecutor { + static { + System.loadLibrary(nativeLibararyName); + } + + public MonitorEnterExecutor_1Subclass(boolean monitorEnter, + boolean monitorEntered) { + super(monitorEnter, monitorEntered); + } + + protected void synchronizedBlock() { + // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here + synchronized (this) { + } + } + + // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here + synchronized protected void synchronizedMethod() { + } + + // call JNI methods MonitorEnter and MonitorExit for 'this' object + protected native void nativeJNIMonitorEnter(); +} + +/* + * Subclass of MonitorEnterExecutor, defines its own event methods(copy of parent + * method), intended for event filters test + */ +class MonitorEnterExecutor_2Subclass extends MonitorEnterExecutor_1Subclass { + static { + System.loadLibrary(nativeLibararyName); + } + + public MonitorEnterExecutor_2Subclass(boolean monitorEnter, + boolean monitorEntered) { + super(monitorEnter, monitorEntered); + } + + protected void synchronizedBlock() { + // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here + synchronized (this) { + } + } + + // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here + synchronized protected void synchronizedMethod() { + } + + // call JNI methods MonitorEnter and MonitorExit for 'this' object + protected native void nativeJNIMonitorEnter(); +} + +/* + * Class is used as base debuggee in tests for following events and event requests: + * - MonitorContendedEnterRequest / MonitorContendedEnterEvent + * - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent + * - MonitorWaitRequest / MonitorWaitEvent + * - MonitorWaitedRequest / MonitorWaitedEvent + */ +public class MonitorEventsDebuggee extends JDIEventsDebuggee { + public static void main(String[] args) { + MonitorEventsDebuggee debuggee = new MonitorEventsDebuggee(); + debuggee.doTest(args); + } + + protected void createActionsExecutors(String description, int eventsCount) { + boolean monitorEnter = description + .contains(JDIEventsDebugger.EventType.MONITOR_CONTENTED_ENTER + .name()); + boolean monitorEntered = description + .contains(JDIEventsDebugger.EventType.MONITOR_CONTENTED_ENTERED + .name()); + boolean monitorWait = description + .contains(JDIEventsDebugger.EventType.MONITOR_WAIT.name()); + boolean monitorWaited = description + .contains(JDIEventsDebugger.EventType.MONITOR_WAITED.name()); + + if (monitorEnter || monitorEntered || monitorWait || monitorWaited) { + createActionsExecutors(monitorEnter, monitorEntered, monitorWait, + monitorWaited, eventsCount); + } else + throw new TestBug( + "Invalid command format (required event not specified)"); + } + + private List eventsData = new ArrayList(); + + protected void clearResults() { + super.clearResults(); + eventsData.clear(); + } + + private void createActionsExecutors(boolean monitorEnter, + boolean monitorEntered, boolean monitorWait, boolean monitorWaited, + int actionsCount) { + EventActionsThread thread; + + // create 3 instances of generating objects of 3 different classes (for + // event filters tests) + if (monitorEnter || monitorEntered) { + thread = new EventActionsThread(new MonitorEnterExecutor( + monitorEnter, monitorEntered), actionsCount); + thread.start(); + eventActionsExecutorsPool.add(thread); + + thread = new EventActionsThread(new MonitorEnterExecutor_1Subclass( + monitorEnter, monitorEntered), actionsCount); + thread.start(); + eventActionsExecutorsPool.add(thread); + + thread = new EventActionsThread(new MonitorEnterExecutor_2Subclass( + monitorEnter, monitorEntered), actionsCount); + thread.start(); + eventActionsExecutorsPool.add(thread); + } + + // create 3 instances of generating objects of 3 different classes (for + // event filters tests) + if (monitorWait || monitorWaited) { + thread = new EventActionsThread(new MonitorWaitExecutor( + monitorWait, monitorWaited), actionsCount); + thread.start(); + eventActionsExecutorsPool.add(thread); + + thread = new EventActionsThread(new MonitorWaitExecutor_1Subclass( + monitorWait, monitorWaited), actionsCount); + thread.start(); + eventActionsExecutorsPool.add(thread); + + thread = new EventActionsThread(new MonitorWaitExecutor_2Subclass( + monitorWait, monitorWaited), actionsCount); + thread.start(); + eventActionsExecutorsPool.add(thread); + } + } + + // start event generating threads and wait when all this threads finish + // execution + // override parent method because of Thread.join() used in parent method + // generates unexpected MonitorWait/MonitorWaited events + protected void startExecution() { + if (eventActionsExecutorsPool.size() == 0) { + throw new TestBug("ActionsExecutors were not created"); + } + + for (EventActionsThread thread : eventActionsExecutorsPool) { + thread.startExecution(); + } + + // wait completion of test threads in separate thread to free thread listening commands + executionControllingThread = new Thread( + new Runnable() { + public void run() { + boolean executionCompleted; + do { + try { + // give time to event generators + Thread.sleep(500); + } catch (InterruptedException e) { + unexpectedException(e); + } + executionCompleted = true; + for (EventActionsThread thread : eventActionsExecutorsPool) { + if (thread.isAlive()) { + executionCompleted = false; + break; + } + } + } while (!executionCompleted); + + completeExecution(); + } + }); + + executionControllingThread.start(); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebuggee.java new file mode 100644 index 00000000000..3240f1f9c82 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebuggee.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.*; +import java.util.*; +import nsk.share.locks.LockingThread; +import nsk.share.TestBug; + +/* + * Class is used as base debuggee in tests for ThreadReference.ownedMonitorsAndFrames(). + * + * Class handle commands for creating threads which acquires and relinquish locks in different ways, + * nsk.share.locks.LockingThread is used for this purposes. + * + * Information about acquired monitors can be stored in static array 'monitorsInfo' and in this way this + * data is available for debugger. + */ +public class OwnedMonitorsDebuggee extends AbstractJDIDebuggee { + // command:threadName:stackFrameDescription + public static final String COMMAND_CREATE_LOCKING_THREAD = "createLockingThread"; + + // command:threadName + public static final String COMMAND_STOP_LOCKING_THREAD = "stopLockingThread"; + + // command:threadName + public static final String COMMAND_UPDATE_MONITOR_INFO = "updateMonitorInfo"; + + // command:threadName + public static final String COMMAND_EXIT_SINGLE_FRAME = "exitSingleFrame"; + + // command:threadName:monitorIndex + public static final String COMMAND_RELINQUISH_MONITOR = "relinquishMonitor"; + + // command:threadName + public static final String COMMAND_ACQUIRE_RELINQUISHED_MONITOR = "acquireRelinquishedMonitor"; + + // from this array information about acquired monitors is available for debugger + // (this class is used in stress tests where several tests are executed consecutively, but in this case using of + // static array shouldn't cause problems because of before using of array 'monitorsInfo' debugger + // uses COMMAND_UPDATE_MONITOR_INFO which updates this array with latest data, so excution of one test shouldn't + // affect other tests) + public static LockingThread.DebugMonitorInfo monitorsInfo[]; + + private boolean returnJNIMonitors; + + public final static String mainThreadName = "OwnedMonitorDebuggeeMainThread"; + + protected String[] doInit(String[] args) { + Thread.currentThread().setName(mainThreadName); + + args = super.doInit(args); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equalsIgnoreCase("-returnJNIMonitors")) { + returnJNIMonitors = true; + } else + standardArgs.add(args[i]); + } + + return standardArgs.toArray(new String[] {}); + } + + public boolean parseCommand(String command) { + if (super.parseCommand(command)) + return true; + + StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command)); + tokenizer.whitespaceChars(':', ':'); + tokenizer.wordChars('_', '_'); + + try { + if (command.startsWith(COMMAND_ACQUIRE_RELINQUISHED_MONITOR)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String threadName = tokenizer.sval; + + acquireRelinquishMonitor(threadName); + + return true; + } else if (command.startsWith(COMMAND_RELINQUISH_MONITOR)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String threadName = tokenizer.sval; + + if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) + throw new TestBug("Invalid command format: " + command); + + int monitorIndex = (int) tokenizer.nval; + + relinquishMonitor(threadName, monitorIndex); + + return true; + } else if (command.startsWith(COMMAND_CREATE_LOCKING_THREAD)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String threadName = tokenizer.sval; + + List stackFramesDescription = new ArrayList(); + + while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) { + stackFramesDescription.add(tokenizer.sval); + } + + createLockingThread(threadName, stackFramesDescription); + return true; + } else if (command.startsWith(COMMAND_STOP_LOCKING_THREAD)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String threadName = tokenizer.sval; + + stopLockingThread(threadName); + + return true; + } else if (command.startsWith(COMMAND_UPDATE_MONITOR_INFO)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String threadName = tokenizer.sval; + + updateMonitorInfo(threadName); + + return true; + } else if (command.startsWith(COMMAND_EXIT_SINGLE_FRAME)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String threadName = tokenizer.sval; + + exitSingleFrame(threadName); + + return true; + } + } catch (IOException e) { + throw new TestBug("Invalid command format: " + command); + } + + return false; + } + + public void acquireRelinquishMonitor(String threadName) { + LockingThread thread = getThread(threadName); + thread.acquireRelinquishedMonitor(); + + thread.waitState(); + updateMonitorInfo(threadName); + } + + public void relinquishMonitor(String threadName, int monitorIndex) { + LockingThread thread = getThread(threadName); + thread.relinquishMonitor(monitorIndex); + + thread.waitState(); + updateMonitorInfo(threadName); + } + + private void updateMonitorInfo(String threadName) { + LockingThread thread = getThread(threadName); + monitorsInfo = thread.getMonitorsInfo(returnJNIMonitors); + } + + private Map threads = new TreeMap(); + + private LockingThread getThread(String threadName) { + LockingThread thread = threads.get(threadName); + + if (thread == null) + throw new TestBug("Locking thread with name: " + threadName + " was not created"); + + return thread; + } + + private void stopLockingThread(String threadName) { + LockingThread thread = getThread(threadName); + thread.stopLockingThread(); + thread.waitState(); + + updateMonitorInfo(threadName); + } + + private void exitSingleFrame(String threadName) { + LockingThread thread = getThread(threadName); + thread.exitSingleFrame(); + thread.waitState(); + + updateMonitorInfo(threadName); + } + + private void createLockingThread(String threadName, List stackFramesDescription) { + if (threads.get(threadName) != null) + throw new TestBug("Locking thread with name: " + threadName + " already exists"); + + LockingThread thread = new LockingThread(log, stackFramesDescription); + thread.setName(threadName); + thread.start(); + thread.waitState(); + + threads.put(threadName, thread); + + updateMonitorInfo(threadName); + } + + public static void main(String args[]) { + OwnedMonitorsDebuggee debuggee = new OwnedMonitorsDebuggee(); + debuggee.doTest(args); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebugger.java new file mode 100644 index 00000000000..1c183b248af --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebugger.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.*; +import java.util.*; +import com.sun.jdi.*; + +import nsk.share.Consts; + +/* + * Class is used as base debugger in tests for ThreadReference.ownedMonitorsAndFrames(). + * + * In all this test similar scenario is used: + * - debugger VM force debugge VM to create test thread which acquires different monitors + * - when test thread acquire all monitors debuggee save information about all acquired monitors in special array 'monitorsInfo' + * - debugger read data from 'monitorsInfo' and compare it with data returned by ThreadReference.ownedMonitorsAndFrames() + */ +public class OwnedMonitorsDebugger extends TestDebuggerType2 { + + /* + * debug data about monitor acquired by debuggee test thread, + * intended to compare with data returned by ThreadReference.ownedMonitorsAndFrames + */ + public static class DebugMonitorInfo { + // create DebugMonitorInfo using mirror of instance of nsk.share.locks.LockingThread.DebugMonitorInfo + DebugMonitorInfo(ObjectReference debuggeeMirror) { + monitor = (ObjectReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("monitor")); + stackDepth = ((IntegerValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("stackDepth"))).intValue(); + thread = (ThreadReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("thread")); + } + + public DebugMonitorInfo(ObjectReference monitor, int stackDepth, ThreadReference thread) { + this.monitor = monitor; + this.stackDepth = stackDepth; + this.thread = thread; + } + + public ObjectReference monitor; + + public int stackDepth; + + public ThreadReference thread; + } + + public static void main(String argv[]) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + return new OwnedMonitorsDebugger().runIt(argv, out); + } + + protected boolean canRunTest() { + if (!vm.canGetMonitorFrameInfo()) { + log.display("TEST CANCELED due to: vm.canGetMonitorFrameInfo() = false"); + return false; + } else + return super.canRunTest(); + } + + protected String debuggeeClassName() { + return OwnedMonitorsDebuggee.class.getName(); + } + + // read debuggee's array 'monitorsInfo' containing information about acquired monitors + protected List getDebugMonitorsInfo() { + List result = new ArrayList(); + + ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs()); + ArrayReference monitorsInfo = (ArrayReference) referenceType.getValue(referenceType.fieldByName("monitorsInfo")); + + for (int i = 0; i < monitorsInfo.length(); i++) + result.add(new DebugMonitorInfo((ObjectReference) monitorsInfo.getValue(i))); + + return result; + } + + private boolean compare(MonitorInfo actual, DebugMonitorInfo expected) { + boolean success = true; + + if (actual.stackDepth() != expected.stackDepth) { + setSuccess(false); + success = false; + log.complain("Expected and actual monitor(" + actual.monitor() + ") stack depth differs, expected: " + expected.stackDepth + " actual: " + + actual.stackDepth()); + } + + if (!actual.thread().equals(expected.thread)) { + setSuccess(false); + success = false; + log.complain("Expected and actual monitor(" + actual.monitor() + " thread differs, expected: " + expected.thread + " actual: " + + actual.thread()); + } + + return success; + } + + protected void compare(List actualData, List expectedData) { + boolean success = true; + + // compare total amount of monitors + if (actualData.size() != expectedData.size()) { + setSuccess(false); + success = false; + log.complain("Number of expected monitors and actual ones differs"); + log.complain("Expected: " + expectedData.size() + ", actual: " + actualData.size()); + } + + // check that all expected monitors are contained in 'actualData' + for (DebugMonitorInfo expectedMonitorInfo : expectedData) { + boolean isMonitorFound = false; + + for (MonitorInfo actualMonitorInfo : actualData) { + if (expectedMonitorInfo.monitor.equals(actualMonitorInfo.monitor())) { + isMonitorFound = true; + + if (!compare(actualMonitorInfo, expectedMonitorInfo)) + success = false; + + break; + } + } + + if (!isMonitorFound) { + setSuccess(false); + success = false; + log.complain("Expected monitor not found in result of ownedMonitorsAndFrames(): " + expectedMonitorInfo.monitor); + } + } + + // check that all monitors from 'actualData' are contained in + // 'expectedData' + for (MonitorInfo actualMonitorInfo : actualData) { + boolean isMonitorFound = false; + + for (DebugMonitorInfo expectedMonitorInfo : expectedData) { + if (actualMonitorInfo.monitor().equals(expectedMonitorInfo.monitor)) { + isMonitorFound = true; + break; + } + } + + if (!isMonitorFound) { + setSuccess(false); + success = false; + log.complain("Unexpected monitor in result of ownedMonitorsAndFrames(): " + actualMonitorInfo.monitor() + " Depth: " + + actualMonitorInfo.stackDepth() + " Thread: " + actualMonitorInfo.thread()); + } + } + + if (!success) + logDebugInfo(actualData, expectedData); + } + + private void logDebugInfo(List actualData, List expectedData) { + log.display("ACTUAL MONITORS (total " + actualData.size() + "):"); + + ThreadReference thread = null; + + for (MonitorInfo monitorInfo : actualData) { + log.display("Monitor: " + monitorInfo.monitor()); + log.display("Depth: " + monitorInfo.stackDepth()); + log.display("Thread: " + monitorInfo.thread()); + if (thread == null) + thread = monitorInfo.thread(); + } + + log.display("EXPECTED MONITORS (total " + expectedData.size() + "):"); + + for (DebugMonitorInfo monitorInfo : expectedData) { + log.display("Monitor: " + monitorInfo.monitor); + log.display("Depth: " + monitorInfo.stackDepth); + log.display("Thread: " + monitorInfo.thread); + if (thread == null) + thread = monitorInfo.thread; + } + + if (thread != null) { + try { + log.display("Thread frames:"); + for (StackFrame frame : thread.frames()) { + Location location = frame.location(); + log.display(location.declaringType().name() + "." + location.method().name() + ", line: " + location.lineNumber()); + } + } catch (Exception e) { + unexpectedException(e); + } + } + } + + /* + * Check that ThreadReference.ownedMonitorsAndFrames() returns correct + * data before calling this method debuggee should save information about + * acquired monitors in special array 'monitorsInfo', + * debugger forces debuggee to do it using command 'COMMAND_UPDATE_MONITOR_INFO' + */ + protected void checkMonitorInfo(ThreadReference threadReference) { + List actualData = null; + + try { + actualData = threadReference.ownedMonitorsAndFrames(); + } catch (Exception e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + + List expectedData = getDebugMonitorsInfo(); + + compare(actualData, expectedData); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugConnectors.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugConnectors.java new file mode 100644 index 00000000000..6c5bc524a6f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugConnectors.java @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * A Super class for pluggable connectors used by + * nsk/jdi/PlugConnectors tests + */ + +package nsk.share.jdi; + +import com.sun.jdi.*; +import com.sun.jdi.connect.*; +import java.io.*; +import java.util.*; + +public class PlugConnectors implements Connector { + + String plugConnectorName = "Undefined_PlugConnector_Name"; + String plugConnectorDescription = "Undefined_PlugConnector_Description"; + Transport plugConnectorTransport = new PlugConnectorsTransport(); + Map plugConnectorDefaultArguments = new HashMap(); + + /* + * Simple implementation of Connector.Argument + */ + public static class TestArgument implements Connector.Argument { + String argName; + String argLabel; + String argDescription; + String argStringValue; + boolean argMustSpecify; + + public TestArgument( + String argName, + String argLabel, + String argDescription, + String argValue, + boolean argMustSpecify) { + + this.argName = argName; + this.argLabel = argLabel; + this.argDescription = argDescription; + this.argStringValue = argValue; + this.argMustSpecify = argMustSpecify; + } + + public String name() { + return argName; + } + + public String label() { + return argLabel; + } + + public String description() { + return argDescription; + } + + public String value() { + return argStringValue; + } + + public void setValue(String argValue) { + this.argStringValue = argValue; + } + + public boolean isValid(String argValue) { + if ( argValue != null ) { + if (argValue.length() > 0) { + return true; + } + } + return false; + } + + public boolean mustSpecify() { + return argMustSpecify; + } + } // end of TestArgument static class + + /* + * Simple implementation of Connector.StringArgument + */ + public static class TestStringArgument extends TestArgument implements Connector.StringArgument { + + public TestStringArgument( String argName, + String argLabel, + String argDescription, + String argValue, + boolean argMustSpecify) { + + super(argName, argLabel, argDescription, argValue, argMustSpecify); + } + + } // end of TestStringArgument static class + + /* + * Simple implementation of Connector.IntegerArgument + */ + public static class TestIntegerArgument extends TestArgument implements Connector.IntegerArgument { + + int argIntValue; + int minArgIntValue; + int maxArgIntValue; + + public TestIntegerArgument(String argName, + String argLabel, + String argDescription, + int argValue, + int minArgIntValue, + int maxArgIntValue, + boolean argMustSpecify) { + + super(argName, argLabel, argDescription, "" + argValue, argMustSpecify); + this.argIntValue = argValue; + this.minArgIntValue = minArgIntValue; + this.maxArgIntValue = maxArgIntValue; + + } + + public int intValue() { + return argIntValue; + } + + public boolean isValid(int value) { + if ( value >= minArgIntValue && value <= maxArgIntValue ) { + return true; + } + return false; + } + + public boolean isValid(String stringValue) { + int intValue; + try { + intValue = Integer.parseInt(stringValue); + } catch (NumberFormatException exception) { + return false; + } + return isValid(intValue); + } + + public int max() { + return maxArgIntValue; + } + + public int min() { + return minArgIntValue; + } + + public void setValue(int value) { + argIntValue = value; + } + + public String stringValueOf(int value) { + return "" + value; + } + + } // end of TestIntegerArgument static class + + /* + * Simple implementation of Connector.BooleanArgument + */ + public static class TestBooleanArgument extends TestArgument implements Connector.BooleanArgument { + + static final String argStringValueTrue = "true"; + static final String argStringValueFalse = "false"; + boolean argBooleanValue; + + public TestBooleanArgument(String argName, + String argLabel, + String argDescription, + boolean argValue, + boolean argMustSpecify) { + + super(argName, argLabel, argDescription, + argValue ? argStringValueTrue : argStringValueFalse, + argMustSpecify); + this.argBooleanValue = argValue; + + } + + public boolean booleanValue() { + return argBooleanValue; + } + + public boolean isValid(String stringValue) { + if ( argStringValueTrue.equals(stringValue) || argStringValueFalse.equals(stringValue) ) { + return true; + } + return false; + } + + public void setValue(boolean value) { + argBooleanValue = value; + } + + public String stringValueOf(boolean value) { + if ( value ) { + return argStringValueTrue; + } + return argStringValueFalse; + } + + } // end of TestBooleanArgument static class + + /* + * Simple implementation of Connector.SelectedArgument + */ + public static class TestSelectedArgument extends TestArgument implements Connector.SelectedArgument { + + List acceptableArgsList; + + public TestSelectedArgument( String argName, + String argLabel, + String argDescription, + String argValue, + List acceptableArgsList, + boolean argMustSpecify) { + + super(argName, argLabel, argDescription, argValue, argMustSpecify); + this.acceptableArgsList = acceptableArgsList; + } + + public List choices() { + return acceptableArgsList; + } + + public boolean isValid(String stringValue) { + + return acceptableArgsList.contains(stringValue); + } + + } // end of TestSelectedArgument static class + + public PlugConnectors( + String plugConnectorName, + String plugConnectorDescription, + Transport plugConnectorTransport, + Map plugConnectorDefaultArguments + ) { + + this.plugConnectorName = plugConnectorName; + this.plugConnectorDescription = plugConnectorDescription; + this.plugConnectorTransport = plugConnectorTransport; + this.plugConnectorDefaultArguments = plugConnectorDefaultArguments; + } + + public String name() { + return plugConnectorName; + } + + public String description() { + return plugConnectorDescription; + } + + public Transport transport() { + return plugConnectorTransport; + } + + public Map defaultArguments() { + return plugConnectorDefaultArguments; + } + + public VirtualMachine launch(Map arguments) throws + IOException, + IllegalConnectorArgumentsException, + VMStartException { + + String exceptionMessage = "## PlugConnectors: Connector name = '" + + plugConnectorName + "';\nNon-authorized call of launch(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public VirtualMachine attach(Map arguments) throws + java.io.IOException, + IllegalConnectorArgumentsException { + + String exceptionMessage = "## PlugConnectors: Connector name = '" + + plugConnectorName + "';\nNon-authorized call of attach(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public String startListening(Map arguments) throws + java.io.IOException, + IllegalConnectorArgumentsException { + + String exceptionMessage = "## PlugConnectors: Connector name = '" + + plugConnectorName + "';\nNon-authorized call of startListening(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public void stopListening(Map arguments) throws + java.io.IOException, + IllegalConnectorArgumentsException { + + String exceptionMessage = "## PlugConnectors: Connector name = '" + + plugConnectorName + "';\nNon-authorized call of stopListening(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + } + + public VirtualMachine accept(Map arguments) throws + java.io.IOException, + IllegalConnectorArgumentsException { + + String exceptionMessage = "## PlugConnectors: Connector name = '" + + plugConnectorName + "';\nNon-authorized call of accept(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public boolean supportsMultipleConnections() { + + String exceptionMessage = "## PlugConnectors: Connector name = '" + + plugConnectorName + "';\nNon-authorized call of supportsMultipleConnections() method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return false; + } + + public static class PlugConnectorsTransport implements Transport { + + String transportName = "Undefined_Transport_Name"; + + public PlugConnectorsTransport() { + } + + public PlugConnectorsTransport(String transportName) { + this.transportName = transportName; + } + + public String name() { + return transportName; + } + + } // end of PlugConnectorsTransport class + + // Auxiliary general purpose methods for pluggable connectors' tests. + + public static String compareConnectors( + String errorLogPrefixHead, + String errorLogPrefix, + Connector referenceConnector, + Connector checkedConnector) { + + String emptyString = ""; + String errorMessage = emptyString; + + // check that connectors have the same name + String referenceConnectorName = referenceConnector.name(); + String checkedConnectorName = checkedConnector.name(); + if ( ! referenceConnectorName.equals(checkedConnectorName) ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked pluggable Connector has unexpected name:\n" + + errorLogPrefix + "Expected Connector's name = '" + referenceConnectorName + "'\n" + + errorLogPrefix + "Actual Connector's name = '" + checkedConnectorName + "'\n"; + } + + // check that connectors have the same description + String referenceConnectorDescription = referenceConnector.description(); + String checkedConnectorDescription = checkedConnector.description(); + if ( ! referenceConnectorDescription.equals(checkedConnectorDescription) ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked pluggable Connector has unexpected description:\n" + + errorLogPrefix + "Expected Connector's description = '" + referenceConnectorDescription + "'\n" + + errorLogPrefix + "Actual Connector's description = '" + checkedConnectorDescription + "'\n"; + } + + // check that connectors have the same transport name + String referenceConnectorTransportName = referenceConnector.transport().name(); + String checkedConnectorTransportName = checkedConnector.transport().name(); + if ( ! referenceConnectorTransportName.equals(checkedConnectorTransportName) ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked pluggable Connector has unexpected transport name:\n" + + errorLogPrefix + "Expected Connector's transport name = '" + referenceConnectorTransportName + "'\n" + + errorLogPrefix + "Actual Connector's transport name = '" + checkedConnectorTransportName + "'\n"; + } + + // check that connectors have the same number of default arguments + int referenceConnectorArgumentsNumber = referenceConnector.defaultArguments().size(); + int checkedConnectorArgumentsNumber = checkedConnector.defaultArguments().size(); + if ( referenceConnectorArgumentsNumber != checkedConnectorArgumentsNumber ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked pluggable Connector has unexpected number of default arguments:\n" + + errorLogPrefix + "Expected number of default arguments = '" + referenceConnectorArgumentsNumber + "'\n" + + errorLogPrefix + "Actual number of default arguments = '" + checkedConnectorArgumentsNumber + "'\n"; + } + + + return errorMessage; + } // end of compareConnectors(...) method + + public static String compareConnectorArguments( + String errorLogPrefixHead, + String errorLogPrefix, + Connector.Argument referenceArgument, + Connector.Argument checkedArgument) { + + String emptyString = ""; + String errorMessage = emptyString; + + if ( referenceArgument == null ) { + errorMessage = + errorLogPrefixHead + "Reference connector's argument is null!\n"; + } + + if ( checkedArgument == null ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked connector's argument is null!\n"; + } + + if ( ! errorMessage.equals(emptyString) ) { + return errorMessage; + } + + String referenceArgumentName = referenceArgument.name(); + String checkedArgumentName = checkedArgument.name(); + if ( ! referenceArgumentName.equals(checkedArgumentName) ) { + errorMessage = + errorLogPrefixHead + "Checked connector's argument has unexpected name:\n" + + errorLogPrefix + "Expected connector's argument name = '" + referenceArgumentName + "'\n" + + errorLogPrefix + "Actual connector's argument name = '" + checkedArgumentName + "'"; + return errorMessage; + } + + String referenceArgumentLabel = referenceArgument.label(); + String checkedArgumentLabel = checkedArgument.label(); + if ( ! referenceArgumentLabel.equals(checkedArgumentLabel) ) { + errorMessage = + errorLogPrefixHead + "Checked connector's argument has unexpected label:\n" + + errorLogPrefix + "Expected connector's argument label = '" + referenceArgumentLabel + "'\n" + + errorLogPrefix + "Actual connector's argument label = '" + checkedArgumentLabel + "'"; + return errorMessage; + } + + String referenceArgumentDescription = referenceArgument.description(); + String checkedArgumentDescription = checkedArgument.description(); + if ( ! referenceArgumentDescription.equals(checkedArgumentDescription) ) { + errorMessage = + errorLogPrefixHead + "Checked connector's argument has unexpected description:\n" + + errorLogPrefix + "Expected connector's argument description = '" + referenceArgumentDescription + "'\n" + + errorLogPrefix + "Actual connector's argument description = '" + checkedArgumentDescription + "'"; + return errorMessage; + } + + String referenceArgumentValue = referenceArgument.value(); + String checkedArgumentValue = checkedArgument.value(); + if ( ! referenceArgumentValue.equals(checkedArgumentValue) ) { + errorMessage = + errorLogPrefixHead + "Checked connector's argument has unexpected value:\n" + + errorLogPrefix + "Expected connector's argument value = '" + referenceArgumentValue + "'\n" + + errorLogPrefix + "Actual connector's argument value = '" + checkedArgumentValue + "'"; + return errorMessage; + } + + boolean referenceArgumentMustSpecify = referenceArgument.mustSpecify(); + boolean checkedArgumentMustSpecify = checkedArgument.mustSpecify(); + if ( referenceArgumentMustSpecify != checkedArgumentMustSpecify ) { + errorMessage = + errorLogPrefixHead + "Checked connector's argument has unexpected 'mustSpecify' property:\n" + + errorLogPrefix + "Expected connector's argument 'mustSpecify' property = '" + + referenceArgumentMustSpecify + "'\n" + + errorLogPrefix + "Actual connector's argument 'mustSpecify' property = '" + + checkedArgumentMustSpecify + "'"; + return errorMessage; + } + + if ( referenceArgument instanceof Connector.IntegerArgument ) { + + int referenceArgumentMin = ((Connector.IntegerArgument)referenceArgument).min(); + int checkedArgumentMin = ((Connector.IntegerArgument)checkedArgument).min(); + if ( referenceArgumentMin != checkedArgumentMin ) { + errorMessage = + errorLogPrefixHead + "Checked connector's integer argument has unexpected min value:\n" + + errorLogPrefix + "Expected connector's argument min value = " + + referenceArgumentMin + "\n" + + errorLogPrefix + "Actual connector's argument min value = " + + checkedArgumentMin + "\n"; + } + + int referenceArgumentMax = ((Connector.IntegerArgument)referenceArgument).max(); + int checkedArgumentMax = ((Connector.IntegerArgument)checkedArgument).max(); + if ( referenceArgumentMax != checkedArgumentMax ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked connector's integer argument has unexpected max value:\n" + + errorLogPrefix + "Expected connector's argument max value = " + + referenceArgumentMax + "\n" + + errorLogPrefix + "Actual connector's argument max value = " + + checkedArgumentMax + "\n"; + } + + } + + if ( referenceArgument instanceof Connector.SelectedArgument ) { + + List referenceArgumentChoices = ((Connector.SelectedArgument)referenceArgument).choices(); + List checkedArgumentChoices = ((Connector.SelectedArgument)checkedArgument).choices(); + + int referenceArgumentChoicesSize = referenceArgumentChoices.size(); + int checkedArgumentChoicesSize = checkedArgumentChoices.size(); + + if ( referenceArgumentChoicesSize != checkedArgumentChoicesSize) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked connector's Selected argument has unexpected choices' size:\n" + + errorLogPrefix + "Expected size = '" + + referenceArgumentChoicesSize + "'\n" + + errorLogPrefix + "Actual size = " + + checkedArgumentChoicesSize; + return errorMessage; + } + + for (int i=0; i < referenceArgumentChoicesSize; i++) { + String referenceArgumentChoice = (String)(referenceArgumentChoices.get(i)); + if ( ! checkedArgumentChoices.contains(referenceArgumentChoice) ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked connector's Selected argument has NOT expected choices' element:\n" + + errorLogPrefix + "Expected choices' element = '" + + referenceArgumentChoice + "'\n"; + } + + String checkedArgumentChoice = (String)(checkedArgumentChoices.get(i)); + if ( ! referenceArgumentChoices.contains(checkedArgumentChoice) ) { + errorMessage = errorMessage + + errorLogPrefixHead + "Checked connector's Selected argument has unexpected choices' element:\n" + + errorLogPrefix + "Unexpected choices' element = '" + + checkedArgumentChoice + "'\n"; + } + } + } + return errorMessage; + } // end of compareConnectorArguments(...) method + + public static Connector.Argument getConnectorDefaultArgument( + Connector connector, + String argumentName) { + + Connector.Argument foundArgument = null; + + Map connectorDefaultArguments = connector.defaultArguments(); + Object[] defaultArgumentsArray = connectorDefaultArguments.values().toArray(); + + for (int i=0; i < defaultArgumentsArray.length; i++) { + Connector.Argument connectorArgument = (Connector.Argument)defaultArgumentsArray[i]; + if ( argumentName.equals(connectorArgument.name()) ) { + foundArgument = connectorArgument; + break; + } + } + return foundArgument; + } + +} // end of PlugConnectors class diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugTransportService.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugTransportService.java new file mode 100644 index 00000000000..4ebfcac418f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugTransportService.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * A Super class for Transport Services used by + * nsk/jdi/PlugConnectors tests + */ + +package nsk.share.jdi; + +import com.sun.jdi.*; +import com.sun.jdi.connect.*; +import com.sun.jdi.connect.spi.*; +import java.io.*; +import java.util.*; + +public class PlugTransportService extends TransportService { + + String plugTransportServiceName = "Undefined_PlugTransportService_Name"; + String plugTransportServiceDescription = "Undefined_PlugTransportService_Description"; + TransportService.Capabilities plugTransportServiceCapabilities = new TestCapabilities(); + + /* + * Simple implementation of TransportService.Capabilities + */ + public static class TestCapabilities extends TransportService.Capabilities { + boolean supportsAcceptTimeout = false; + boolean supportsAttachTimeout = false; + boolean supportsHandshakeTimeout = false; + boolean supportsMultipleConnections = false; + + public TestCapabilities() { + } + + public TestCapabilities( + boolean supportsAcceptTimeout, + boolean supportsAttachTimeout, + boolean supportsHandshakeTimeout, + boolean supportsMultipleConnections) { + + this.supportsAcceptTimeout = supportsAcceptTimeout; + this.supportsAttachTimeout = supportsAttachTimeout; + this.supportsHandshakeTimeout = supportsHandshakeTimeout; + this.supportsMultipleConnections = supportsMultipleConnections; + } + + public boolean supportsAcceptTimeout() { + return supportsAcceptTimeout; + } + + public boolean supportsAttachTimeout() { + return supportsAttachTimeout; + } + + public boolean supportsHandshakeTimeout() { + return supportsHandshakeTimeout; + } + + public boolean supportsMultipleConnections() { + return supportsMultipleConnections; + } + + } // end of TestCapabilities static class + + /* + * Simple implementation of TransportService.ListenKey + */ + public static class TestListenKey extends TransportService.ListenKey { + String address = null; + + public TestListenKey() { + } + + public TestListenKey(String address) { + + this.address = address; + } + + public String address() { + return address; + } + + } // end of TestListenKey static class + + public PlugTransportService() { + } + + public PlugTransportService( + String plugTransportServiceName, + String plugTransportServiceDescription, + TransportService.Capabilities plugTransportServiceCapabilities + ) { + + this.plugTransportServiceName = plugTransportServiceName; + this.plugTransportServiceDescription = plugTransportServiceDescription; + this.plugTransportServiceCapabilities = plugTransportServiceCapabilities; + } + + public String name() { + return plugTransportServiceName; + } + + public String description() { + return plugTransportServiceDescription; + } + + public TransportService.Capabilities capabilities() { + return plugTransportServiceCapabilities; + } + + public Connection attach( + String address, + long attachTimeout, + long handshakeTimeout) throws IOException { + + String exceptionMessage = "## PlugTransportService: TransportService name = '" + + plugTransportServiceName + "';\nNon-authorized call of attach(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public TransportService.ListenKey startListening(String address) throws IOException { + + String exceptionMessage = "## PlugTransportService: TransportService name = '" + + plugTransportServiceName + "';\nNon-authorized call of startListening(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public TransportService.ListenKey startListening() throws IOException { + + String exceptionMessage = "## PlugTransportService: TransportService name = '" + + plugTransportServiceName + "';\nNon-authorized call of startListening() method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + public void stopListening(TransportService.ListenKey listenKey) throws IOException { + + String exceptionMessage = "## PlugTransportService: TransportService name = '" + + plugTransportServiceName + "';\nNon-authorized call of stopListening() method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + } + + public Connection accept( + TransportService.ListenKey listenKey, + long acceptTimeout, + long handshakeTimeout) throws IOException { + + String exceptionMessage = "## PlugTransportService: TransportService name = '" + + plugTransportServiceName + "';\nNon-authorized call of accept(...) method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + + return null; + } + + /* + * Simple implementation of Connection + */ + public static class PlugTransportServiceConnection extends Connection { + + public void close() throws IOException { + String exceptionMessage = + "## PlugTransportConnection: \nNon-authorized call of close() method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + } + + public boolean isOpen() { + String exceptionMessage = + "## PlugTransportConnection: \nNon-authorized call of isOpen() method!"; + + if ( true ) { + throw new RuntimeException(exceptionMessage); + } + return false; + } + + public byte[] readPacket() throws IOException { + String exceptionMessage = + "## PlugTransportConnection: \nNon-authorized call of readPacket() method!"; + + if ( true ) { + throw new ClosedConnectionException(exceptionMessage); + } + + if ( true ) { + throw new ClosedConnectionException(); + } + + return null; + } + + public void writePacket(byte[] pkt) throws IOException { + String exceptionMessage = + "## PlugTransportConnection: \nNon-authorized call of writePacket(...) method!"; + + if ( true ) { + throw new ClosedConnectionException(exceptionMessage); + } + + if ( true ) { + throw new ClosedConnectionException(); + } + + } + + } // end of PlugTransportServiceConnection class + +} // end of PlugTransportService class diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebuggee.java new file mode 100644 index 00000000000..32603119704 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebuggee.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.IOException; +import java.io.StreamTokenizer; +import java.io.StringReader; +import nsk.share.Consts; + +/* + * This class is intended for execution several JDI tests in single VM and used together with nsk.share.jdi.SerialExecutionDebugger + * + * SerialExecutionDebuggee handles 2 commands: + * - COMMAND_EXECUTE_DEBUGGEE: : + * initialize 'currentDebuggee' with instance of class 'debuggee_class_name'(this class should + * be subclass of nsk.share.jpda.AbstractDebugeeTest) and execute it's method doTest() + * + * - COMMAND_CLEAR_DEBUGGEE + * set 'currentDebuggee' to null + * + * For more detailed description of serial test execution see SerialExecutionDebugger + */ +public class SerialExecutionDebuggee extends AbstractJDIDebuggee { + public static void main(String args[]) { + new SerialExecutionDebuggee().doTest(args); + } + + // command:[ debugee_parameters] + public static final String COMMAND_EXECUTE_DEBUGGEE = "COMMAND_EXECUTE_DEBUGGEE"; + + public static final String COMMAND_CLEAR_DEBUGGEE = "COMMAND_CLEAR_DEBUGGEE"; + + private AbstractJDIDebuggee currentDebuggee; + + public boolean parseCommand(String command) { + if (super.parseCommand(command)) + return true; + + if (command.startsWith(COMMAND_EXECUTE_DEBUGGEE)) { + String debuggeeClassName = null; + + try { + StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command)); + tokenizer.resetSyntax(); + tokenizer.wordChars(Integer.MIN_VALUE, Integer.MAX_VALUE); + tokenizer.whitespaceChars(':', ':'); + + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) { + log.complain("Invalid command format: " + command); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + debuggeeClassName = tokenizer.sval; + } catch (IOException e) { + log.complain("Invalid command format: " + command); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + try { + // parse debuggee parameters + String[] debuggeeParameters = {}; + + int index = debuggeeClassName.indexOf(' '); + + if (index > 0) { + debuggeeParameters = debuggeeClassName.substring(index).split(" "); + log.display("Debuggee parameters: " + debuggeeClassName.substring(index)); + debuggeeClassName = debuggeeClassName.substring(0, index); + } + + // create debuggee object + Class debuggeeClass = Class.forName(debuggeeClassName); + + if (!AbstractJDIDebuggee.class.isAssignableFrom(debuggeeClass)) { + log.complain("Invalid debugee class: " + debuggeeClass); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + currentDebuggee = (AbstractJDIDebuggee) debuggeeClass.newInstance(); + + // pass to the current debuggee already created objects: + // argHandler, log, pipe + currentDebuggee.initDebuggee(argHandler, log, pipe, debuggeeParameters, false); + } catch (Exception e) { + log.complain("Unexpected exception during debuggee initialization: " + e); + e.printStackTrace(log.getOutStream()); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + try { + // current debuggee performs test + currentDebuggee.doTest(); + + if (currentDebuggee.getSuccess()) { + log.display("Debuggee " + currentDebuggee + " finished successfully"); + } else { + setSuccess(false); + log.complain("Debuggee " + currentDebuggee + "finished with errors"); + } + + return true; + } catch (Exception e) { + log.complain("Unexpected exception during debuggee execution: " + e); + e.printStackTrace(log.getOutStream()); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } else if (command.equals(COMMAND_CLEAR_DEBUGGEE)) { + currentDebuggee = null; + + return true; + } + + return false; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebugger.java new file mode 100644 index 00000000000..5798dde7da3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebugger.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import nsk.share.Consts; +import nsk.share.TestBug; +import nsk.share.jpda.AbstractDebuggeeTest; +import java.io.*; +import java.util.*; + +/* + * This class serial executes several JDI tests based on nsk.share.jdi.TestDebuggerType2 in single VM + * SerialExecutionDebugger is used together with SerialExecutionDebuggee, execution process is following: + * + * - SerialExecutionDebugger reads tests to execute from input file, test description is debugger class name and test's parameters, + * if 'shuffle' option is specified in input file debugger executes tests in random order (input file should contain line "OPTIONS:shuffle"). + * SerialExecutionDebugger can execute tests several times in loop, number of iterations should be specified in input file in following manner: + * OPTIONS:iterations . + * + * - SerialExecutionDebugger starts debuggee VM with main class SerialExecutionDebuggee, + * initializes IOPipe and 'debuggee' object which represents debuggee VM + * + * - for each test from input file: + * + * - SerialExecutionDebugger creates object of current debugger and initializes it with already created pipe and debuggee + * - SerialExecutionDebugger sends command to SerialExecutionDebuggee: 'COMMAND_EXECUTE_DEBUGGEE ' + * (CurrentDebuggeeName name should provide current debugger), and waits READY signal from debuggee + * - SerialExecutionDebuggee parses received command, extracts debugee name, creates object of current debuggee, which should be + * subclass of nsk.share.jpda.AbstractDebuggeeTestName + * - SerialExecutionDebuggee executes current debuggee's method 'doTest()', in this method debuggee sends signal READY + * and waits debugger command + * - SerialExecutionDebugger receives signal READY and executes current debugger's method 'doTest()', in + * this method debugger should perform test + * - when debugger method doTest() finishes SerialExecutionDebugger checks is this test passed or failed and + * sends command QUIT to the current debuggee, and when current debuggee finishes sends command 'COMMAND_CLEAR_DEBUGGEE' to the SerialExecutionDebuggee, + * after this command SerialExecutionDebugger and SerialExecutionDebuggee ready to execute next test + * + * - when all tests was executed SerialExecutionDebugger sends command QUIT to the SerialExecutionDebuggee and exits + * + * SerialExecutionDebugger requires "-configFile " parameter, - file with list of tests for execution + */ +public class SerialExecutionDebugger extends TestDebuggerType2 { + static public void main(String[] args) { + System.exit(Consts.JCK_STATUS_BASE + new SerialExecutionDebugger().runIt(args, System.out)); + } + + public String debuggeeClassName() { + return SerialExecutionDebuggee.class.getName(); + } + + // contains test's debugger class name and test parameters + static class Test { + public Test(String debuggerClassName, String[] arguments) { + this.debuggerClassName = debuggerClassName; + this.arguments = arguments; + } + + public String argumentsToString() { + String result = ""; + + for (String argument : arguments) + result += argument + " "; + + return result; + } + + String debuggerClassName; + + String arguments[]; + } + + private Test tests[]; + + // how many times execute tests + private int iterations = 1; + + // requires "-configFile " parameter, - file with list + // of tests for execution + protected String[] doInit(String args[], PrintStream out) { + args = super.doInit(args, out); + + String configFileName = null; + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-configFile") && (i < args.length - 1)) { + configFileName = args[i + 1]; + i++; + } else + standardArgs.add(args[i]); + } + + if (configFileName == null) { + throw new TestBug("Config file wasn't specified (use option -configFile )"); + } + + tests = parseConfigFile(configFileName); + + if (tests.length == 0) + throw new TestBug("Tests to run were not specified"); + + return standardArgs.toArray(new String[] {}); + } + + // read test names and test parameters from ini-file + private Test[] parseConfigFile(String fileName) { + List result = new ArrayList(); + + boolean shuffle = false; + + try { + File file = new File(fileName); + + LineNumberReader lineReader = new LineNumberReader(new FileReader(file)); + + String line = null; + + while ((line = lineReader.readLine()) != null) { + // skip empty lines and comments started with '#" + if (line.length() == 0 || line.startsWith("#")) + continue; + + if (line.startsWith("OPTIONS:")) { + String arguments[] = line.substring(8).split(" "); + + for (int i = 0; i < arguments.length; i++) { + if (arguments[i].equalsIgnoreCase("shuffle")) + shuffle = true; + else if (arguments[i].equalsIgnoreCase("iterations") && (i < (arguments.length - 1))) { + iterations = Integer.parseInt(arguments[i + 1]); + i++; + } + } + + continue; + } + + StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(line)); + tokenizer.resetSyntax(); + tokenizer.wordChars(Integer.MIN_VALUE, Integer.MAX_VALUE); + tokenizer.whitespaceChars(' ', ' '); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid ini file format"); + + String testClassName = tokenizer.sval; + List parameters = new ArrayList(); + + int token; + while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) { + if (token == StreamTokenizer.TT_WORD) { + if (tokenizer.sval.equals("$CLASSPATH")) + parameters.add(classpath); + else + parameters.add(tokenizer.sval); + } + + if (token == StreamTokenizer.TT_NUMBER) { + parameters.add("" + tokenizer.nval); + } + } + + result.add(new Test(testClassName, parameters.toArray(new String[] {}))); + } + + } catch (IOException e) { + throw new TestBug("Exception during config file parsing: " + e); + } + + if (shuffle) { + if (testWorkDir == null) + throw new TestBug("Debugger requires -testWorkDir parameter"); + + Collections.shuffle(result); + + // save resulted tests sequence in file (to simplify reproducing) + try { + File file = new File(testWorkDir + File.separator + "run.tests"); + file.createNewFile(); + + PrintWriter writer = new PrintWriter(new FileWriter(file)); + + for (Test test : result) { + writer.println(test.debuggerClassName + " " + test.argumentsToString()); + } + + writer.close(); + } catch (IOException e) { + throw new TestBug("Unexpected IOException: " + e); + } + } + + System.out.println("Tests execution order: "); + for (Test test : result) { + System.out.println(test.debuggerClassName + " " + test.argumentsToString()); + } + + return result.toArray(new Test[] {}); + } + + public void doTest() { + + stresser.start(iterations); + + try { + if (iterations == 1) { + /* + * Since many test couldn't be run in single VM twice and test config specifies only 1 iteration don't + * multiple iterations by iterations factor and execute tests once (not depending on iterations factor) + */ + executeTests(); + } else { + while (stresser.continueExecution()) { + if (!executeTests()) { + // if error occured stop execution + break; + } + } + } + } finally { + stresser.finish(); + } + } + + boolean executeTests() { + // maximum execution time of single test + long maxExecutionTime = 0; + + for (Test test : tests) { + long testStartTime = System.currentTimeMillis(); + + TestDebuggerType2 debugger = null; + + try { + // create debugger object + Class debuggerClass = Class.forName(test.debuggerClassName); + + if (!TestDebuggerType2.class.isAssignableFrom(debuggerClass)) { + setSuccess(false); + log.complain("Invalid debugger class: " + debuggerClass); + return false; + } + + // init test debugger, pass to the debugger already created + // objects: argHandler, log, pipe, debuggee, vm + debugger = (TestDebuggerType2) debuggerClass.newInstance(); + debugger.initDebugger(argHandler, log, pipe, debuggee, vm); + debugger.doInit(test.arguments, System.out); + } catch (Exception e) { + setSuccess(false); + log.complain("Unexpected exception during debugger initialization: " + e); + e.printStackTrace(log.getOutStream()); + + return false; + } + + log.display("Execute debugger: " + debugger); + + // send command to the SerialExecutionDebuggee (create debuggee + // object) + pipe.println(SerialExecutionDebuggee.COMMAND_EXECUTE_DEBUGGEE + ":" + debugger.debuggeeClassName()); + + // wait first READY from AbstractDebuggeeTest.doTest() (debuggee + // sends this command when it was initialized and ready for + // test) + if (!isDebuggeeReady()) + return false; + + try { + // here debuggee should be ready for test and current + // debugger may perform test + debugger.doTest(); + + if (debugger.getSuccess()) { + log.display("Debugger " + debugger + " finished successfully"); + } else { + setSuccess(false); + log.complain("Debugger " + debugger + " finished with errors"); + } + } catch (TestBug testBug) { + setSuccess(false); + log.complain("Test bug in " + debugger + ": " + testBug); + testBug.printStackTrace(log.getOutStream()); + } catch (Throwable t) { + setSuccess(false); + log.complain("Unexpected exception during test execution(debugger: " + debugger + "): " + t); + t.printStackTrace(log.getOutStream()); + } + + // send QUIT command to the current debuggee + pipe.println(AbstractDebuggeeTest.COMMAND_QUIT); + + if (!isDebuggeeReady()) + return false; + + // send command to the SerialExecutionDebuggee + pipe.println(SerialExecutionDebuggee.COMMAND_CLEAR_DEBUGGEE); + + if (!isDebuggeeReady()) + return false; + + long testExecutionTime = System.currentTimeMillis() - testStartTime; + + if (testExecutionTime > maxExecutionTime) + maxExecutionTime = testExecutionTime; + + if (maxExecutionTime > stresser.getTimeLeft()) { + log.display("WARNING: stop test execution because of timeout " + + "(max execution time for single test: " + maxExecutionTime + ", time left: " + stresser.getTimeLeft() + ")"); + return false; + } + } + + return true; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass1.java new file mode 100644 index 00000000000..a1af93b76b9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass1.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +/* + * Empty class, used to be sure that there are no instances of this class in target VM + */ +public class TestClass1 { +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass2.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass2.java new file mode 100644 index 00000000000..f2318d02b53 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass2.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +/* + * Empty class, used to be sure that there are no instances of this class in target VM + * Used in tests where subclass of test class is needed + */ +public class TestClass2 extends TestClass1 { +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java new file mode 100644 index 00000000000..02157c626cb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +import java.io.*; + +import nsk.share.*; + +/** + * This class is a template for test debugger. + * It bases on some existed tests for testing of + * JDI requests and events. + * + * Requirements for a test debugger which extends + * this template are as folllows: + * - the subclass must have 'main' and 'run' methods + * defined like: + * public static void main (String argv[]) { + * System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + * } + * + * public static int run (String argv[], PrintStream out) { + * debuggeeName = ; + * return new filter001().runThis(argv, out); + * } + * + * - the subclass must implement 'testRun' method + * which must contain checkings of all test's assertions. + */ +public abstract class TestDebuggerType1 { + + protected static int waitTime; + protected static int testExitCode = Consts.TEST_PASSED; + + protected static Binder binder; + protected static Debugee debuggee; + protected static VirtualMachine vm; + protected static ArgumentHandler argsHandler; + protected static Log log; + protected static String debuggeeName; /* must be assigned in a subclass */ + protected static ReferenceType debuggeeClass; + + protected static EventRequestManager eventRManager; + protected static EventHandler eventHandler; + protected static BreakpointRequest bpRequest /* communication breakpoint */; + protected static volatile int bpCount; + + protected static void display(String message) { + log.display("debugger> " + message); + } + + protected static void complain(String message) { + log.complain("debugger> " + message); + } + + /** + * Should be used in test debugger when assertion failed. + */ + protected static void setFailedStatus(String message) { + complain(message); + testExitCode = Consts.TEST_FAILED; + } + + protected int runThis (String argv[], PrintStream out) { + + argsHandler = new ArgumentHandler(argv); + log = new Log(out, argsHandler); + binder = new Binder(argsHandler, log); + waitTime = argsHandler.getWaitTime() * 60000; + + try { + debuggee = binder.bindToDebugee(debuggeeName); + debuggee.redirectStdout(log, Debugee.DEBUGEE_STDERR_LOG_PREFIX); + vm = debuggee.VM(); + eventRManager = vm.eventRequestManager(); + + eventHandler = new EventHandler(debuggee, log); + eventHandler.startListening(); + + debuggeeClass = waitForClassPrepared(debuggeeName); + + /* A debuggee class must define 'methodForCommunication' + * method and invoke it in points of synchronization + * with a debugger. + */ + setCommunicationBreakpoint(debuggeeClass,"methodForCommunication"); + + display("TESTING BEGINS"); + + // after waitForClassPrepared() main debuggee thread is suspended, resume it before test start + display("RESUME DEBUGGEE VM"); + vm.resume(); + + testRun(); + + display("TESTING ENDS"); + + display("Waiting for debuggee's exit..."); + eventHandler.waitForVMDisconnect(); + + int status = EventHandler.getStatus(); + if (status != 0) { + setFailedStatus("Event handler returned unexpected exit status: " + status); + } else { + display("Event handler thread exited."); + } + + debuggee.endDebugee(); + status = debuggee.getStatus(); + if (status != (Consts.TEST_PASSED + Consts.JCK_STATUS_BASE)) { + setFailedStatus("Debuggee returned unexpected exit status: " + status); + } else { + display("Debuggee PASSED."); + } + + } catch (VMDisconnectedException e) { + setFailedStatus("Unexpected VMDisconnectedException"); + e.printStackTrace(log.getOutStream()); + throw new Failure(e.getMessage()); + + } catch (Exception e) { + setFailedStatus("Unexpected exception : " + e.getMessage()); + e.printStackTrace(log.getOutStream()); + display("Forcing debuggee to exit..."); + vm.exit(Consts.TEST_PASSED + Consts.JCK_STATUS_BASE); + } + + return testExitCode; + } + + /** + * This method which be implemented in all test debuggers + * and must contain checking of test assertions. + */ + protected abstract void testRun(); + + /** + * Waits until debuggee class is prepared. + * + */ + private ReferenceType waitForClassPrepared(String className) { + ClassPrepareRequest cpRequest = eventRManager.createClassPrepareRequest(); + cpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD); + cpRequest.addClassFilter(className); + + ClassPrepareEvent event = (ClassPrepareEvent)eventHandler.waitForRequestedEvent( + new EventRequest[]{cpRequest}, waitTime, true); + ReferenceType refType = event.referenceType(); + if (!refType.name().equals(className)) + throw new Failure("Unexpected class name for received ClassPrepareEvent: " + refType.name() + + "\n\texpected name: " + debuggeeName); + display("Received ClassPrepareEvent for debuggee class: " + refType.name()); + return refType; + }; + + /** + * Sets up breakpoint request which serves for synchronization + * between debugger and debuggee. + * + */ + private void setCommunicationBreakpoint(ReferenceType refType, String methodName) { + Method method = debuggee.methodByName(refType, methodName); + Location location = null; + try { + location = method.allLineLocations().get(0); + } catch (AbsentInformationException e) { + throw new Failure(e); + } + bpRequest = debuggee.makeBreakpoint(location); + + bpRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); + bpRequest.putProperty("number", "zero"); + bpRequest.enable(); + + eventHandler.addListener( + new EventHandler.EventListener() { + public boolean eventReceived(Event event) { + if (event instanceof BreakpointEvent && bpRequest.equals(event.request())) { + synchronized(eventHandler) { + display("Received communication breakpoint event."); + bpCount++; + eventHandler.notifyAll(); + } + return true; + } + return false; + } + } + ); + } + + /** + * Waits for synchronization breakpoint event and checks + * up if there are more test case to check. + * + * Note: debuggee VM shouldn't be suspended when this method + * is called + * + * @return true if there are more test case to check, + * false otherwise or debuggee is disconnected. + */ + protected boolean shouldRunAfterBreakpoint() { + display("shouldRunAfterBreakpoint: entered"); + boolean shouldRun = true; + + long timeToFinish = System.currentTimeMillis() + waitTime; + long timeLeft = waitTime; + synchronized(eventHandler) { + while (!EventHandler.isDisconnected() && bpCount <= 0 && timeLeft > 0) { + display("shouldRunAfterBreakpoint: waiting for breakpoint event during 1 sec."); + try { + eventHandler.wait(1000); + } catch (InterruptedException e) { + throw new Failure(e); + } + timeLeft = timeToFinish - System.currentTimeMillis(); + } + } + if (timeLeft <= 0 && bpCount <= 0) { + setFailedStatus("shouldRunAfterBreakpoint: had not received breakpoint event during waitTime."); + shouldRun = false; + + } else if (bpCount > 0) { + display("shouldRunAfterBreakpoint: received breakpoint event."); + bpCount--; + } + + if (!EventHandler.isDisconnected()) { + try { + int instruction = ((IntegerValue) + (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); + + if (instruction == 0) { + display("shouldRunAfterBreakpoint: received instruction from debuggee to finish."); + shouldRun = false; + } + } catch (VMDisconnectedException e) { + shouldRun = false; + } + } else { + shouldRun = false; + } + + if (shouldRun) { + display("shouldRunAfterBreakpoint: exited with true."); + } else { + display("shouldRunAfterBreakpoint: exited with false."); + } + return shouldRun; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType2.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType2.java new file mode 100644 index 00000000000..28d1d815e0d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType2.java @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.io.*; +import java.util.*; +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; +import nsk.share.*; +import nsk.share.jpda.*; +import nsk.share.test.StressOptions; +import nsk.share.test.Stresser; + +/* + * Class can be used as base debugger class in jdi tests. + * Class contains common method for initializing log, debugee, pipe, vm, and several common auxiliary methods. + * Sublcass should implement doTest() and, if needed, doInit(parse command line parameters) and canRunTest(check if VM support tested functionality) + */ +public class TestDebuggerType2 { + public class EventListenerThread extends Thread { + private EventRequest eventRequest; + + private Event event; + + private Wicket wicket = new Wicket(); + + public EventListenerThread(EventRequest eventRequest) { + this.eventRequest = eventRequest; + } + + public void run() { + wicket.unlock(); + + try { + event = debuggee.waitingEvent(eventRequest, argHandler.getWaitTime() * 60000); + } catch (InterruptedException e) { + // ignore + } + } + + public void waitStartListen() { + wicket.waitFor(); + } + + public Event getEvent() { + try { + // wait when EventListenerThread complete execution + this.join(); + } catch (InterruptedException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + } + + return event; + } + } + + protected ArgumentHandler argHandler; + + protected Log log; + + protected IOPipe pipe; + + protected Debugee debuggee; + + protected VirtualMachine vm; + + /* + * this method is called from nsk.share.jdi.SerialExecutionDebugger to set for debugger + * already created instances of ArgumentHandler, Log, IOPipe, Debugee, VirtualMachine + */ + public void initDebugger(ArgumentHandler argHandler, Log log, IOPipe pipe, Debugee debuggee, VirtualMachine vm) { + this.argHandler = argHandler; + this.log = log; + this.pipe = pipe; + this.debuggee = debuggee; + this.vm = vm; + } + + private boolean success = true; + + protected void setSuccess(boolean value) { + success = value; + } + + protected boolean getSuccess() { + return success; + } + + // class name used during initialization + protected String debuggeeClassName() { + return null; + } + + // select only class name if debuggeeClassName() returns className + debuggee parameters + protected String debuggeeClassNameWithoutArgs() { + String className = debuggeeClassName(); + + int index = className.indexOf(' '); + if (index > 0) { + return className.substring(0, index); + } else + return className; + } + + protected String classpath; + + protected String testWorkDir; + + // initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments + // (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options) + // support -testClassPath parameter: path to find classes for custom classloader in debuggee VM + // (note that in this method stressOptions and stresser are created, so if subclasses override this method + // overrided version should first call super.doInit()) + protected String[] doInit(String args[], PrintStream out) { + stressOptions = new StressOptions(args); + stresser = new Stresser(stressOptions); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-testClassPath") && (i < args.length - 1)) { + classpath = args[i + 1]; + i++; + } else if (args[i].equals("-testWorkDir") && (i < args.length - 1)) { + testWorkDir = args[i + 1]; + + if (testWorkDir.endsWith(File.separator)) { + testWorkDir = testWorkDir.substring(0, testWorkDir.length() - 1); + } + + i++; + } else + standardArgs.add(args[i]); + } + + return standardArgs.toArray(new String[] {}); + } + + protected void doTest() { + setSuccess(false); + throw new TestBug("TEST BUG: method doTest not implemented"); + } + + protected Stresser stresser; + protected StressOptions stressOptions; + + // initialize log, debuggee, pipe + public void init(String args[], PrintStream out) { + argHandler = new ArgumentHandler(doInit(args, out)); + log = new Log(out, argHandler); + Binder binder = new Binder(argHandler, log); + debuggee = binder.bindToDebugee(debuggeeClassName()); + pipe = debuggee.createIOPipe(); + debuggee.redirectStderr(log, "Debugger.err> "); + vm = debuggee.VM(); + debuggee.resume(); + + String command = pipe.readln(); + + if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) { + setSuccess(false); + log.complain("TEST BUG: unknown debuggee's command: " + command); + } + } + + // check that vm support tested functions + protected boolean canRunTest() { + return true; + } + + // send quit command to debuggee + protected void quitDebuggee() { + pipe.println(AbstractDebuggeeTest.COMMAND_QUIT); + debuggee.waitFor(); + + int debStat = debuggee.getStatus(); + + if (debStat != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) { + setSuccess(false); + log.complain("TEST FAILED: debuggee's process finished with status: " + debStat); + } else + log.display("Debuggee's process finished with status: " + debStat); + + } + + // init test, execute test, quit debuggee + protected int runIt(String args[], PrintStream out) { + init(args, out); + + try { + if (canRunTest()) + doTest(); + } catch (TestBug testBug) { + setSuccess(false); + log.complain("Test bug: " + testBug); + testBug.printStackTrace(log.getOutStream()); + } catch (Throwable t) { + setSuccess(false); + log.complain("Unexpected exception: " + t); + t.printStackTrace(log.getOutStream()); + } + + quitDebuggee(); + + if (getSuccess()) { + log.display("TEST PASSED"); + return Consts.TEST_PASSED; + } else { + log.display("TEST FAILED"); + return Consts.TEST_FAILED; + } + } + + // check the debuggee completed pervious command and is ready for new one + protected boolean isDebuggeeReady() { + String command = pipe.readln(); + + if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) { + setSuccess(false); + log.complain("TEST BUG: unknown debuggee's command: " + command); + + return false; + } + + return true; + } + + // find in debuggee VM instance of object with given class and check + // that there is only one instance of this class + protected ObjectReference findSingleObjectReference(String className) { + ReferenceType referenceType = debuggee.classByName(className); + + if (referenceType == null) + throw new TestBug("There is no class '" + className + "' in debuggee"); + + List instances = referenceType.instances(0); + + if (instances.size() == 0) + throw new TestBug("There are no instances of class '" + className + "' in debuggee"); + + if (instances.size() > 1) + throw new TestBug("There are more than one(" + instances.size() + ") instance of '" + className + " in debuggee"); + + return instances.get(0); + } + + protected BreakpointEvent waitForBreakpoint(BreakpointRequest breakpointRequest) { + BreakpointEvent breakpointEvent; + + try { + breakpointEvent = (BreakpointEvent) debuggee.waitingEvent(breakpointRequest, argHandler.getWaitTime() * 60000); + } catch (InterruptedException e) { + setSuccess(false); + e.printStackTrace(log.getOutStream()); + log.complain("unexpected InterruptedException: " + e); + + breakpointEvent = null; + } + + if (breakpointEvent == null) { + setSuccess(false); + log.complain("Didn't get expected breakpoint event"); + } + + return breakpointEvent; + } + + + private boolean currentSuccess = false; + protected void forceGC() { + pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_GC); + if (!isDebuggeeReady()) + return; + currentSuccess = getSuccess(); + } + + // Get GC statistics + protected void resetStatusIfGC() { + pipe.println(AbstractDebuggeeTest.COMMAND_GC_COUNT); + String command = pipe.readln(); + if (command.startsWith(AbstractDebuggeeTest.COMMAND_GC_COUNT)) { + if (!isDebuggeeReady()) { + return; + } + if (Integer.valueOf(command.substring(AbstractDebuggeeTest.COMMAND_GC_COUNT.length() + 1)) > 0) { + log.display("WARNING: The GC worked during tests. Results are skipped."); + setSuccess(currentSuccess); + } + return; + } + setSuccess(false); + } + + + protected BreakpointRequest defaultBreakpointRequest; + + protected void initDefaultBreakpoint() { + defaultBreakpointRequest = debuggee.makeBreakpoint(debuggee.classByName(debuggeeClassNameWithoutArgs()), + AbstractDebuggeeTest.DEFAULT_BREAKPOINT_METHOD_NAME, AbstractDebuggeeTest.DEFAULT_BREAKPOINT_LINE); + + defaultBreakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); + defaultBreakpointRequest.enable(); + } + + protected void removeDefaultBreakpoint() { + defaultBreakpointRequest.disable(); + debuggee.getEventRequestManager().deleteEventRequest(defaultBreakpointRequest); + defaultBreakpointRequest = null; + } + + protected Value createVoidValue() { + return vm.mirrorOfVoid(); + } + + // force debuggee call 'TestDebuggeeType2.breakpointMethod()' + protected BreakpointEvent forceBreakpoint() { + pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_BREAKPOINT); + + BreakpointEvent event = waitForBreakpoint(defaultBreakpointRequest); + + return event; + } + + protected void unexpectedException(Throwable t) { + setSuccess(false); + log.complain("Unexpected exception: " + t); + t.printStackTrace(log.getOutStream()); + } + + protected void display(String msg) { + log.display(msg); + } + + protected void complain(String msg) { + log.complain("debugger FAILURE> " + msg + "\n"); + } + + protected boolean isJFR_active() { + return debuggee.isJFR_active(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestInterfaceImplementer1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestInterfaceImplementer1.java new file mode 100644 index 00000000000..3d6a46d5a55 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestInterfaceImplementer1.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +interface Interface1 { + +} + +interface Interface2 { + +} + +interface Interface3 { + +} + +interface Interface4 { + +} + +interface Interface5 { + +} + +/* + * Empty class, used to be sure that there are no instances of this class in target VM + * Used in tests where interface implementer is needed + */ +public class TestInterfaceImplementer1 implements Interface1, Interface2, Interface3, Interface4, Interface5 { + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ThreadState.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ThreadState.java new file mode 100644 index 00000000000..92b70f1a4a8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ThreadState.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jdi; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.TimeUnit; + +import nsk.share.Failure; + +/** + * Functions to set and wait for states in threads. + * Used to sync main thread and debuggee thread. + */ +public class ThreadState { + private final Lock lock = new ReentrantLock(); + private final Condition cond = lock.newCondition(); + private volatile String currentState; + private long timeoutMs; + + public ThreadState(String startState, long timeoutMs) { + currentState = startState; + this.timeoutMs = timeoutMs; + } + + /** + * Set new state. + */ + public void setState(String newState) { + lock.lock(); + try { + log(MSG_SET_STATE, newState); + currentState = newState; + cond.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * Wait for the specified state. + * Throws Failure if timeout. + */ + public void waitForState(String waitState) { + lock.lock(); + try { + log(MSG_WAIT_STATE, waitState); + while (!currentState.equals(waitState)) { + if (!cond.await(timeoutMs, TimeUnit.MILLISECONDS)) { + throw new Failure(format(MSG_TIMEOUT, waitState)); + } + } + log(MSG_GOT_STATE, waitState); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new Failure(e); + } finally { + lock.unlock(); + } + } + + /** + * Simple helper that sets a new state and then wait for another state. + */ + public void setAndWait(String newState, String waitState) { + setState(newState); + waitForState(waitState); + } + + private static final String MSG_TIMEOUT = "ThreadState(thread='%s', state='%s') timeout waiting for %s"; + private static final String MSG_SET_STATE = "ThreadState(thread='%s', state='%s') set state to %s"; + private static final String MSG_WAIT_STATE = "ThreadState(thread='%s', state='%s') waiting for state %s"; + private static final String MSG_GOT_STATE = "ThreadState(thread='%s', state='%s') got state %s"; + + private String format(String pattern, String state) { + final String threadName = Thread.currentThread().getName(); + return String.format(pattern, threadName, currentState, state); + } + + private void log(String pattern, String state) { + System.out.println(format(pattern, state)); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ValueConversionDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ValueConversionDebugger.java new file mode 100644 index 00000000000..8e15c688b41 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ValueConversionDebugger.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi; + +import java.lang.reflect.*; +import nsk.share.*; +import nsk.share.jpda.ConversionUtils; +import com.sun.jdi.*; + +/* + * Class contains several common methods used by tests checking that values are + * correctly converted as a result of JDI interface work (e.g. when method + * 'ObjectReference.setValue(Field, Value)' is called) + */ +public class ValueConversionDebugger extends TestDebuggerType2 { + + protected static enum ValueType { + BYTE, + CHAR, + SHORT, + INT, + LONG, + FLOAT, + DOUBLE + } + + /* + * short aliases for ValueType members + */ + protected static ValueType BYTE = ValueType.BYTE; + protected static ValueType CHAR = ValueType.CHAR; + protected static ValueType SHORT = ValueType.SHORT; + protected static ValueType INT = ValueType.INT; + protected static ValueType LONG = ValueType.LONG; + protected static ValueType FLOAT = ValueType.FLOAT; + protected static ValueType DOUBLE = ValueType.DOUBLE; + + /* + * Is information lost when given PrimitiveValue converted to the + * primitive type representing by the destType + */ + public static boolean informationLoss(PrimitiveValue value, Class destType) { + /* + * Use reflection here to avoid large nested switches + * (construct method name, method is located in the nsk.share.jpda.ConversionUtils) + */ + String methodNameToCall = "informationLoss"; + + Object param = null; + + if (value instanceof ByteValue) { + methodNameToCall += "ByteTo"; + param = new Byte(value.byteValue()); + } else if (value instanceof ShortValue) { + methodNameToCall += "ShortTo"; + param = new Short(value.shortValue()); + } else if (value instanceof CharValue) { + methodNameToCall += "CharTo"; + param = new Character(value.charValue()); + } else if (value instanceof IntegerValue) { + methodNameToCall += "IntTo"; + param = new Integer(value.intValue()); + } else if (value instanceof LongValue) { + methodNameToCall += "LongTo"; + param = new Long(value.longValue()); + } else if (value instanceof FloatValue) { + methodNameToCall += "FloatTo"; + param = new Float(value.floatValue()); + } else if (value instanceof DoubleValue) { + methodNameToCall += "DoubleTo"; + param = new Double(value.doubleValue()); + } else + throw new IllegalArgumentException("Illegal PrimitiveValue: " + value); + + if (!destType.isPrimitive()) + throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type"); + + if (destType == Byte.TYPE) { + methodNameToCall += "Byte"; + } else if (destType == Short.TYPE) { + methodNameToCall += "Short"; + } else if (destType == Character.TYPE) { + methodNameToCall += "Char"; + } else if (destType == Integer.TYPE) { + methodNameToCall += "Int"; + } else if (destType == Long.TYPE) { + methodNameToCall += "Long"; + } else if (destType == Float.TYPE) { + methodNameToCall += "Float"; + } else if (destType == Double.TYPE) { + methodNameToCall += "Double"; + } else + throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type"); + + java.lang.reflect.Method method; + try { + method = ConversionUtils.class.getMethod(methodNameToCall, param.getClass()); + } catch (NoSuchMethodException e) { + throw new Failure("Unexpected exception: " + e, e); + } + + try { + return (Boolean)method.invoke(null, new Object[]{param}); + } catch (IllegalAccessException e) { + throw new Failure("Unexpected exception: " + e, e); + } catch (InvocationTargetException e) { + throw new Failure("Unexpected exception: " + e, e); + } + } + + /* + * Is given PrimitiveValue can be converted to the primitive type represented by the + * destType without information loss + */ + public static boolean isValidConversion(PrimitiveValue value, Class destType) { + return !informationLoss(value, destType); + } + + /* + * Method is used in subclasses for creation of tested values + * (reflection is used to simplify coding) + */ + protected PrimitiveValue createValue(Object arr, int arrayIndex) { + PrimitiveValue value; + + if (arr instanceof byte[]) { + value = debuggee.VM().mirrorOf(Array.getByte(arr,arrayIndex)); + } else if (arr instanceof char[]) { + value = debuggee.VM().mirrorOf(Array.getChar(arr,arrayIndex)); + } else if (arr instanceof double[]) { + value = debuggee.VM().mirrorOf(Array.getDouble(arr,arrayIndex)); + } else if (arr instanceof float[]) { + value = debuggee.VM().mirrorOf(Array.getFloat(arr,arrayIndex)); + } else if (arr instanceof int[]) { + value = debuggee.VM().mirrorOf(Array.getInt(arr,arrayIndex)); + } else if (arr instanceof long[]) { + value = debuggee.VM().mirrorOf(Array.getLong(arr,arrayIndex)); + } else if (arr instanceof short[]) { + value = debuggee.VM().mirrorOf(Array.getShort(arr,arrayIndex)); + } else { + setSuccess(false); + throw new TestBug("Unexpected object was passed in the 'createValue': " + arr); + } + + return value; + } + + /* + * used by subclasses for debug output + * (modified in the method 'isValidConversion') + */ + protected String lastConversion; + + /* + * Is given PrimitiveValue can be converted to the primitive type represented by the given type + * without information loss + */ + protected boolean isValidConversion(ValueType type, PrimitiveValue value) { + com.sun.jdi.Type fromType = value.type(); + + boolean ret = false; + lastConversion = " conversion from " + + value + "(" + fromType + ")" + " to "; + switch (type) { + case BYTE: + byte b = value.byteValue(); + ret = isValidConversion(value, Byte.TYPE); + lastConversion += b + "(byte)"; + break; + case CHAR: + char c = value.charValue(); + ret = isValidConversion(value, Character.TYPE); + lastConversion += Integer.toHexString(c) + "(char)"; + break; + case DOUBLE: + double d = value.doubleValue(); + ret = isValidConversion(value, Double.TYPE); + lastConversion += d + "(double)"; + break; + case FLOAT: + float f = value.floatValue(); + ret = isValidConversion(value, Float.TYPE); + lastConversion += f + "(float)"; + break; + case INT: + int i = value.intValue(); + ret = isValidConversion(value, Integer.TYPE); + lastConversion += i + "(int)"; + break; + case LONG: + long j = value.longValue(); + ret = isValidConversion(value, Long.TYPE); + lastConversion += j + "(long)"; + break; + case SHORT: + short s = value.shortValue(); + ret = isValidConversion(value, Short.TYPE); + lastConversion += s + "(short)"; + break; + default: + throw new IllegalArgumentException("Invalid type: " + type); + } + return ret; + } + + /* + * Used in subclasses to check that given PrimitiveValue was correctly converted as a result + * of JDI interface work (retValue - conversion result) + * ( + * example: + * test assigns DoubleValue = 1.5 (value) to the byte Field (retValue - ByteValue = 1), + * in this case we should check that value.byteValue() == retValue.byteValue() + * ) + */ + protected void checkValueConversion(PrimitiveValue value, PrimitiveValue retValue) { + boolean res; + + if (retValue instanceof ByteValue) { + res = value.byteValue() != retValue.byteValue(); + } else if (retValue instanceof ShortValue) { + res = value.shortValue() != retValue.shortValue(); + } else if (retValue instanceof CharValue) { + res = value.charValue() != retValue.charValue(); + } else if (retValue instanceof IntegerValue) { + res = value.intValue() != retValue.intValue(); + } else if (retValue instanceof LongValue) { + res = value.longValue() != retValue.longValue(); + } else if (retValue instanceof FloatValue) { + res = value.floatValue() != retValue.floatValue(); + } else if (retValue instanceof DoubleValue) { + res = value.doubleValue() != retValue.doubleValue(); + } else { + throw new TestBug("Invalid value type in the 'checkValueConversion': " + retValue.type().name()); + } + + if (res) { + setSuccess(false); + complain("Conversion error"); + complain("From type: " + value.type().name() + ", to type: " + retValue.type().name()); + complain(retValue + " != " + value); + display(""); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/InstallSDE.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/InstallSDE.java new file mode 100644 index 00000000000..d537f90d971 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/InstallSDE.java @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi.sde; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import nsk.share.Consts; + +/* + * Inserts in class file 'SourceDebugExtension' attribute based on input .SMAP file. + */ +public class InstallSDE { + static final String nameSDE = "SourceDebugExtension"; + + private byte[] orig; + + private byte[] sdeAttr; + + private byte[] gen; + + private int origPos = 0; + + private int genPos = 0; + + private int sdeIndex; + + public static void install(File inClassFile, File smapFile, File outClassFile, boolean verbose) throws IOException { + new InstallSDE(inClassFile, smapFile, outClassFile, verbose); + } + + public static void install(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose) throws IOException { + new InstallSDE(aOrig, aSdeAttr, outClassFile, verbose); + } + + public static void install(File inOutClassFile, File attrFile, boolean verbose) throws IOException { + File tmpFile = new File(inOutClassFile.getPath() + "tmp"); + + new InstallSDE(inOutClassFile, attrFile, tmpFile, verbose); + + if (!inOutClassFile.delete()) { + throw new IOException("inOutClassFile.delete() failed"); + } + if (!tmpFile.renameTo(inOutClassFile)) { + throw new IOException("tmpFile.renameTo(inOutClassFile) failed"); + } + } + + private static void abort(String msg) { + System.err.println(msg); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + + private InstallSDE(File inClassFile, File attrFile, File outClassFile, boolean verbose) throws IOException { + if (!inClassFile.exists()) { + abort("no such file: " + inClassFile); + } + if (!attrFile.exists()) { + abort("no such file: " + attrFile); + } + + // get the bytes + orig = readWhole(inClassFile); + sdeAttr = readWhole(attrFile); + gen = new byte[orig.length + sdeAttr.length + 100]; + + // do it + addSDE(verbose); + + // write result + FileOutputStream outStream = new FileOutputStream(outClassFile); + outStream.write(gen, 0, genPos); + outStream.close(); + } + + private InstallSDE(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose) throws IOException { + orig = aOrig; + sdeAttr = aSdeAttr; + gen = new byte[orig.length + sdeAttr.length + 100]; + + // do it + addSDE(verbose); + + // write result + FileOutputStream outStream = new FileOutputStream(outClassFile); + outStream.write(gen, 0, genPos); + outStream.close(); + } + + private byte[] readWhole(File input) throws IOException { + FileInputStream inStream = new FileInputStream(input); + try { + return readWhole(inStream, (int) input.length()); + } finally { + inStream.close(); + } + } + + private byte[] readWhole(InputStream inStream, int len) throws IOException { + byte[] bytes = new byte[len]; + + if (inStream.read(bytes, 0, len) != len) { + abort("expected size: " + len); + } + + return bytes; + } + + private void addSDE(boolean verbose) throws UnsupportedEncodingException { + copy(4 + 2 + 2); // magic min/maj version + int constantPoolCountPos = genPos; + int constantPoolCount = readU2(); + writeU2(constantPoolCount); + // copy old constant pool return index of SDE symbol, if found + sdeIndex = copyConstantPool(constantPoolCount, verbose); + if (sdeIndex < 0) { + // if "SourceDebugExtension" symbol not there add it + writeUtf8ForSDE(); + + // increment the countantPoolCount + sdeIndex = constantPoolCount; + ++constantPoolCount; + randomAccessWriteU2(constantPoolCountPos, constantPoolCount); + + if (verbose) { + System.out.println("SourceDebugExtension not found, installed at: " + sdeIndex); + } + } else { + if (verbose) { + System.out.println("SourceDebugExtension found at: " + sdeIndex); + } + } + copy(2 + 2 + 2); // access, this, super + int interfaceCount = readU2(); + writeU2(interfaceCount); + if (verbose) { + System.out.println("interfaceCount: " + interfaceCount); + } + copy(interfaceCount * 2); + copyMembers(verbose); // fields + copyMembers(verbose); // methods + int attrCountPos = genPos; + int attrCount = readU2(); + writeU2(attrCount); + if (verbose) { + System.out.println("class attrCount: " + attrCount); + } + // copy the class attributes, return true if SDE attr found (not copied) + if (!copyAttrs(attrCount, verbose)) { + // we will be adding SDE and it isn't already counted + ++attrCount; + randomAccessWriteU2(attrCountPos, attrCount); + if (verbose) { + System.out.println("class attrCount incremented"); + } + } + writeAttrForSDE(sdeIndex); + } + + private void copyMembers(boolean verbose) { + int count = readU2(); + writeU2(count); + if (verbose) { + System.out.println("members count: " + count); + } + for (int i = 0; i < count; ++i) { + copy(6); // access, name, descriptor + int attrCount = readU2(); + writeU2(attrCount); + if (verbose) { + System.out.println("member attr count: " + attrCount); + } + copyAttrs(attrCount, verbose); + } + } + + private boolean copyAttrs(int attrCount, boolean verbose) { + boolean sdeFound = false; + for (int i = 0; i < attrCount; ++i) { + int nameIndex = readU2(); + // don't write old SDE + if (nameIndex == sdeIndex) { + sdeFound = true; + if (verbose) { + System.out.println("SDE attr found"); + } + } else { + writeU2(nameIndex); // name + int len = readU4(); + writeU4(len); + copy(len); + if (verbose) { + System.out.println("attr len: " + len); + } + } + } + return sdeFound; + } + + private void writeAttrForSDE(int index) { + writeU2(index); + writeU4(sdeAttr.length); + for (int i = 0; i < sdeAttr.length; ++i) { + writeU1(sdeAttr[i]); + } + } + + private void randomAccessWriteU2(int pos, int val) { + int savePos = genPos; + genPos = pos; + writeU2(val); + genPos = savePos; + } + + private int readU1() { + return ((int) orig[origPos++]) & 0xFF; + } + + private int readU2() { + int res = readU1(); + return (res << 8) + readU1(); + } + + private int readU4() { + int res = readU2(); + return (res << 16) + readU2(); + } + + private void writeU1(int val) { + gen[genPos++] = (byte) val; + } + + private void writeU2(int val) { + writeU1(val >> 8); + writeU1(val & 0xFF); + } + + private void writeU4(int val) { + writeU2(val >> 16); + writeU2(val & 0xFFFF); + } + + private void copy(int count) { + for (int i = 0; i < count; ++i) { + gen[genPos++] = orig[origPos++]; + } + } + + private byte[] readBytes(int count) { + byte[] bytes = new byte[count]; + for (int i = 0; i < count; ++i) { + bytes[i] = orig[origPos++]; + } + return bytes; + } + + private void writeBytes(byte[] bytes) { + for (int i = 0; i < bytes.length; ++i) { + gen[genPos++] = bytes[i]; + } + } + + private int copyConstantPool(int constantPoolCount, boolean verbose) throws UnsupportedEncodingException { + int sdeIndex = -1; + // copy const pool index zero not in class file + if ( verbose ) + System.out.println("cp count=" + constantPoolCount); + for (int i = 1; i < constantPoolCount; ++i) { + int tag = readU1(); + writeU1(tag); + if ( verbose ) + System.out.println(i + ": tag=" + tag); + switch (tag) { + case 7: // Class + case 8: // String + case 16: // MethodType + copy(2); + break; + case 15: // MethodHandle + copy(3); + break; + case 9: // Field + case 10: // Method + case 11: // InterfaceMethod + case 3: // Integer + case 4: // Float + case 12: // NameAndType + case 17: // InvokeDynamic_17 (will go away) + case 18: // InokeDynamic + copy(4); + break; + case 5: // Long + case 6: // Double + copy(8); + ++i; + break; + case 1: // Utf8 + int len = readU2(); + writeU2(len); + byte[] utf8 = readBytes(len); + String str = new String(utf8, "UTF-8"); + if (verbose) { + System.out.println(i + " read class attr -- '" + str + "'"); + } + if (str.equals(nameSDE)) { + sdeIndex = i; + } + writeBytes(utf8); + break; + default: + abort("unexpected tag: " + tag); + break; + } + } + return sdeIndex; + } + + private void writeUtf8ForSDE() { + int len = nameSDE.length(); + writeU1(1); // Utf8 tag + writeU2(len); + for (int i = 0; i < len; ++i) { + writeU1(nameSDE.charAt(i)); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebuggee.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebuggee.java new file mode 100644 index 00000000000..b9bd30b6f2e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebuggee.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi.sde; + +import java.lang.reflect.Method; +import nsk.share.TestBug; +import nsk.share.jdi.*; + +public class SDEDebuggee extends AbstractJDIDebuggee { + public static String mainThreadName = "SDEDebuggee_mainThread"; + + // command:class_name + public static String COMMAND_EXECUTE_TEST_METHODS = "executeTestMethods"; + + public static void main(String args[]) { + new SDEDebuggee().doTest(args); + } + + protected String[] doInit(String[] args) { + args = super.doInit(args); + + if (classpath == null) + throw new TestBug("Debuggee requires '-testClassPath' parameter"); + + Thread.currentThread().setName(mainThreadName); + + return args; + } + + public boolean parseCommand(String command) { + if (super.parseCommand(command)) + return true; + + if (command.startsWith(COMMAND_EXECUTE_TEST_METHODS)) { + // extract class name + String split[] = command.split(":"); + + if ((split.length != 2) || (split[1].length() == 0)) + throw new TestBug(""); + + executeTestMethods(split[1]); + breakpointMethod(); + + return true; + } + + return false; + } + + // create instance of given class and execute all methods which names start + // with 'sde_testMethod' + private void executeTestMethods(String className) { + TestClassLoader classLoader = new TestClassLoader(); + classLoader.setClassPath(classpath); + + try { + Class klass = classLoader.loadClass(className); + Object testObject = klass.newInstance(); + + for (Method method : klass.getDeclaredMethods()) { + if (method.getName().startsWith("sde_testMethod")) + method.invoke(testObject, new Object[] {}); + } + } catch (Exception e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + + throw new TestBug("Unexpected exception: " + e); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebugger.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebugger.java new file mode 100644 index 00000000000..5fa95a7133e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebugger.java @@ -0,0 +1,1123 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi.sde; + +import java.io.*; +import java.nio.channels.FileChannel; +import java.util.*; +import com.sun.jdi.*; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.StepEvent; +import nsk.share.ClassFileFinder; +import nsk.share.TestBug; +import nsk.share.jdi.EventHandler; +import nsk.share.jdi.TestDebuggerType2; + +/* + * Class is used as base debugger for SDE tests. + * + * This class contains several methods called 'prepareDefaultPatchedClassFile_TypeXXX' which create + * class file with added SourceDebugExtension attribute and return debug information about created file. + * (this methods was moved in SDEDebugger class if similar generated class files were used in 2 or more tests) + * + * + */ +public class SDEDebugger extends TestDebuggerType2 { + protected static final int INIT_LINE = 32; // n.s.j.sde.TestClass1:: + protected static final int METHOD1_LINE = 43; // n.s.j.sde.TestClass1::sde_testMethod1 + protected static final int METHOD2_LINE = 54; // n.s.j.sde.TestClass1::sde_testMethod2 + public static String javaStratumName = "Java"; + + // Set debug data for "Java" stratum for TestClass1 + public static List javaStratumLocations_TestClass1 = new ArrayList(); + + public static String javaSourceName_TestClass1 = "TestClass1.java"; + + public static String javaSourcePath_TestClass1 = "nsk" + File.separator + "share" + File.separator + "jdi" + + File.separator + "sde" + File.separator + "TestClass1.java"; + + static { + for (int i = 0; i < 8; i++) { + javaStratumLocations_TestClass1.add(new DebugLocation(javaSourceName_TestClass1, javaSourcePath_TestClass1, + "", INIT_LINE + i, INIT_LINE + i)); + javaStratumLocations_TestClass1.add(new DebugLocation(javaSourceName_TestClass1, javaSourcePath_TestClass1, + "sde_testMethod1", METHOD1_LINE + i, METHOD1_LINE + i)); + javaStratumLocations_TestClass1.add(new DebugLocation(javaSourceName_TestClass1, javaSourcePath_TestClass1, + "sde_testMethod2", METHOD2_LINE + i, METHOD2_LINE + i)); + } + } + + // insert debug information about "Java" stratum in the given Map + static protected void addJavaLocations(Map testStratumData, boolean setJavaStratumDefault) { + LocationsData locationsData = new LocationsData(javaStratumName); + + if (setJavaStratumDefault) + locationsData.isDefault = true; + + locationsData.paths.add(javaSourcePath_TestClass1); + locationsData.allLocations.addAll(javaStratumLocations_TestClass1); + locationsData.sourceLocations.put(javaSourceName_TestClass1, javaStratumLocations_TestClass1); + + testStratumData.put(javaStratumName, locationsData); + + } + + // common base names for test stratum, stratum source name and stratum + // source path + public static final String testStratumName = "TestStratum"; + + public static final String testStratumSourceName = "testSource"; + + public static final String testStratumSourcePath = "testSourcePath"; + + // Event listener thread which saves all received StepEvents + public class StepEventListener extends EventHandler.EventListener { + // is BreakpointEvent was received (debuggee should stop at breakpoint + // after StepEvents generation) + private volatile boolean breakpointEventReceived; + + private List stepLocations = new ArrayList(); + + public List stepLocations() { + return stepLocations; + } + + public void clearLocations() { + stepLocations.clear(); + } + + public boolean eventReceived(Event event) { + if (event instanceof StepEvent) { + StepEvent stepEvent = (StepEvent) event; + + stepLocations.add(stepEvent.location()); + + vm.resume(); + + return true; + } + // debuggee should stop after event generation + else if (event instanceof BreakpointEvent) { + breakpointEventReceived = true; + vm.resume(); + + return true; + } + + return false; + } + + public void waitBreakpointEvent() { + while (!breakpointEventReceived) + Thread.yield(); + } + } + + // debug information about location (implements Comparable to make possible + // using DebugLocation with java.util.Set) + public static class DebugLocation implements Comparable { + public DebugLocation(String sourceName, String sourcePath, String methodName, int inputLine, int outputLine) { + this.sourceName = sourceName; + this.sourcePath = sourcePath; + this.inputLine = inputLine; + this.outputLine = outputLine; + this.methodName = methodName; + } + + public String sourceName; + + public String sourcePath; + + public String methodName; + + public int inputLine; + + public int outputLine; + + public String toString() { + return "Line number: " + inputLine + " SourceName: " + sourceName + " SourcePath: " + sourcePath; + } + + // compare DebugLocation with com.sun.jdi.Location + public boolean compare(Location location, String stratum) { + try { + if (stratum == null) { + return (location.lineNumber() == inputLine) && location.sourceName().equals(sourceName) + && location.sourcePath().equals(sourcePath); + } else { + return (location.lineNumber(stratum) == inputLine) + && location.sourceName(stratum).equals(sourceName) + && location.sourcePath(stratum).equals(sourcePath); + } + } catch (AbsentInformationException e) { + return false; + } + } + + // used to find locations for given line + public boolean isConform(String sourceName, int lineNumber) { + boolean sourceConform = (sourceName == null ? true : this.sourceName.equals(sourceName)); + + return sourceConform && (this.inputLine == lineNumber); + } + + // implements this method to make possible using DebugLocation with java.util.Set + public int compareTo(DebugLocation location) { + return (this.sourceName.equals(location.sourceName) && this.inputLine == location.inputLine) ? 0 : 1; + } + } + + // Class contains debug information about sources, paths, locations + // available for class + public static class LocationsData { + public LocationsData(String stratumName) { + this.stratumName = stratumName; + } + + public List sourceNames() { + List sourceNames = new ArrayList(); + sourceNames.addAll(sourceLocations.keySet()); + + return sourceNames; + } + + public String stratumName; + + // is stratum default for ReferenceType + public boolean isDefault; + + // locations for source files + public Map> sourceLocations = new TreeMap>(); + + // all locations for stratum + public List allLocations = new ArrayList(); + + // all paths for stratum + public List paths = new ArrayList(); + } + + static protected String locationToString(Location location, String stratum) { + String result; + + result = "Line number: " + (stratum == null ? location.lineNumber() : location.lineNumber(stratum)); + + try { + result += (" Source name: " + (stratum == null ? location.sourceName() : location.sourceName(stratum))); + } catch (AbsentInformationException e) { + result += (" Source name: " + " INFORMATION IS ABSENT"); + } + + try { + result += (" Source path: " + (stratum == null ? location.sourcePath() : location.sourcePath(stratum))); + } catch (AbsentInformationException e) { + result += (" Source path: " + " INFORMATION IS ABSENT"); + } + + return result; + } + + // seach class file for given class and create copy of this class file in + // 'testWorkDir' directory + protected File createLocalClassfileCopy(String className) throws IOException { + int index = className.lastIndexOf("."); + + String path; + + if (index < 0) + path = ""; + else + path = className.substring(0, index).replace(".", "/"); + + File dirs = new File(testWorkDir + "/" + path); + dirs.mkdirs(); + + File oldFile = null; + { + java.nio.file.Path tmp = ClassFileFinder.findClassFile(className, classpath); + oldFile = tmp == null ? null : tmp.toFile(); + } + File newFile = copyFile(oldFile, + testWorkDir + "/" + className.replace(".", "/") + ".class"); + + return newFile; + } + + // create class file with multiple strata + protected void savePathcedClassFile(String className, SmapGenerator smapGenerator, String smapFileName) { + File patchedClassFile = null; + + try { + patchedClassFile = createLocalClassfileCopy(className); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Unexpected IO exception: " + e); + } + + smapFileName = testWorkDir + "/" + smapFileName; + smapGenerator.setOutputFileName(smapFileName); + + File smapFile = null; + + try { + smapFile = smapGenerator.saveToFile(smapFileName); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Unexpected IO exception: " + e); + } + + log.display("Add for class " + className + " following SDE: "); + log.display(smapGenerator.getString()); + + try { + InstallSDE.install(patchedClassFile, smapFile, false); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new TestBug("Unexpected IO exception: " + e); + } + } + + // common for SDE tests debuggee name + protected String debuggeeClassName() { + if (classpath == null) { + throw new TestBug("Debugger requires 'testClassPath' parameter"); + } + + return SDEDebuggee.class.getName() + " -testClassPath " + testWorkDir; + } + + // parses common for all SDE - tests parameters + protected String[] doInit(String args[], PrintStream out) { + args = super.doInit(args, out); + + if (classpath == null) { + throw new TestBug("Debugger requires 'testClassPath' parameter"); + } + if (testWorkDir == null) { + throw new TestBug("Debugger requires 'testWorkDir' parameter"); + } + + return args; + } + + // single input line is mapped to the single output line, test stratum has + // single source + protected Map prepareDefaultPatchedClassFile_Type1(String className, int testStratumCount, + boolean setJavaStratumDefault) { + /* + * "Java" "TestStratum" + * + * + * 32 --> 1000, source1 + * 33 --> 1001, source1 + * ... + * ... + * 39 --> 1007, source1 + * + * sde_testMethod1 + * + * 43 --> 1100, source1 + * 44 --> 1101, source1 + * ... + * ... + * 50 --> 1107, source1 + * + * sde_testMethod1 + * 54 --> 1200, source1 + * 55 --> 1201, source1 + * ... + * ... + * 61 --> 1207, source1 + */ + + Map testStratumData = new TreeMap(); + + String smapFileName = "TestSMAP.smap"; + SmapGenerator smapGenerator = new SmapGenerator(); + + for (int i = 0; i < testStratumCount; i++) { + String stratumName = testStratumName + (i + 1); + + LocationsData locationsData = new LocationsData(stratumName); + + String sourceName = testStratumSourceName + (i + 1); + String sourcePath = testStratumSourcePath + (i + 1); + + locationsData.paths.add(sourcePath); + + SmapStratum smapStratum = new SmapStratum(stratumName); + + List sourceLocations = new ArrayList(); + + int baseLineNumber = 1000 * (i + 1); + + for (int j = 0; j < 8; j++) { + sourceLocations.add(new DebugLocation(sourceName, sourcePath, + "", baseLineNumber + j, INIT_LINE + j)); + sourceLocations.add(new DebugLocation(sourceName, sourcePath, + "sde_testMethod1", baseLineNumber + 100 + j, METHOD1_LINE + j)); + sourceLocations.add(new DebugLocation(sourceName, sourcePath, + "sde_testMethod2", baseLineNumber + 200 + j, METHOD2_LINE + j)); + } + + locationsData.sourceLocations.put(sourceName, sourceLocations); + locationsData.allLocations.addAll(sourceLocations); + + testStratumData.put(stratumName, locationsData); + + smapStratum.addFile(sourceName, sourcePath); + + for (DebugLocation debugLocation : sourceLocations) { + smapStratum.addLineData(debugLocation.inputLine, sourceName, 1, debugLocation.outputLine, 1); + } + + // if setJavaStratumDefault == false do first test stratum default + if (!(setJavaStratumDefault) && (i == 0)) { + locationsData.isDefault = true; + smapGenerator.addStratum(smapStratum, true); + } else + smapGenerator.addStratum(smapStratum, false); + } + + savePathcedClassFile(className, smapGenerator, smapFileName); + + addJavaLocations(testStratumData, setJavaStratumDefault); + + return testStratumData; + } + + // single input line is mapped to the single output line, test stratum has 3 + // sources + protected Map prepareDefaultPatchedClassFile_Type2(String className, int testStratumCount) { + /* + * "Java" "TestStratum" + * + * + * 32 --> 1000, source1, path1 + * 33 --> 1001, source2, path2 + * 34 --> 1002, source3, path3 + * ... + * ... + * + * sde_testMethod1 + * 43 --> 1100, source1, path1 + * 44 --> 1101, source2, path2 + * 45 --> 1102, source3, path3 + * ... + * ... + * + * sde_testMethod2 + * 54 --> 1200, source1, path1 + * 55 --> 1201, source2, path2 + * 56 --> 1207, source3, path3 + * ... + * ... + */ + + Map testStratumData = new TreeMap(); + + String smapFileName = "TestSMAP.smap"; + SmapGenerator smapGenerator = new SmapGenerator(); + + for (int i = 0; i < testStratumCount; i++) { + String stratumName = testStratumName + (i + 1); + SmapStratum smapStratum = new SmapStratum(stratumName); + + LocationsData locationsData = new LocationsData(stratumName); + + String sourceName1 = testStratumSourceName + (i + 1) + "_1"; + String sourcePath1 = testStratumSourcePath + (i + 1) + "_1"; + locationsData.paths.add(sourcePath1); + smapStratum.addFile(sourceName1, sourcePath1); + + String sourceName2 = testStratumSourceName + (i + 1) + "_2"; + String sourcePath2 = testStratumSourcePath + (i + 1) + "_2"; + locationsData.paths.add(sourcePath2); + smapStratum.addFile(sourceName2, sourcePath2); + + String sourceName3 = testStratumSourceName + (i + 1) + "_3"; + String sourcePath3 = testStratumSourcePath + (i + 1) + "_3"; + locationsData.paths.add(sourcePath3); + smapStratum.addFile(sourceName3, sourcePath3); + + List source1Locations = new ArrayList(); + List source2Locations = new ArrayList(); + List source3Locations = new ArrayList(); + + for (int j = 0; j < 8; j++) { + if (j % 3 == 0) { + source1Locations.add(new DebugLocation(sourceName1, sourcePath1, + "", 1000 + j, INIT_LINE + j)); + source1Locations.add(new DebugLocation(sourceName1, sourcePath1, + "sde_testMethod1", 1101 + j, METHOD1_LINE + j)); + source1Locations.add(new DebugLocation(sourceName1, sourcePath1, + "sde_testMethod2", 1201 + j, METHOD2_LINE + j)); + } else if (j % 3 == 1) { + source2Locations.add(new DebugLocation(sourceName2, sourcePath2, + "", 1000 + j, INIT_LINE + j)); + source2Locations.add(new DebugLocation(sourceName2, sourcePath2, + "sde_testMethod1", 1101 + j, METHOD1_LINE + j)); + source2Locations.add(new DebugLocation(sourceName2, sourcePath2, + "sde_testMethod2", 1201 + j, METHOD2_LINE + j)); + } else { + source3Locations.add(new DebugLocation(sourceName3, sourcePath3, + "", 1000 + j, INIT_LINE + j)); + source3Locations.add(new DebugLocation(sourceName3, sourcePath3, + "sde_testMethod1", 1101 + j, METHOD1_LINE + j)); + source3Locations.add(new DebugLocation(sourceName3, sourcePath3, + "sde_testMethod2", 1201 + j, METHOD2_LINE + j)); + } + } + + locationsData.sourceLocations.put(sourceName1, source1Locations); + locationsData.sourceLocations.put(sourceName2, source2Locations); + locationsData.sourceLocations.put(sourceName3, source3Locations); + + locationsData.allLocations.addAll(source1Locations); + locationsData.allLocations.addAll(source2Locations); + locationsData.allLocations.addAll(source3Locations); + + for (DebugLocation debugLocation : locationsData.allLocations) { + smapStratum.addLineData( + debugLocation.inputLine, + debugLocation.sourceName, + 1, + debugLocation.outputLine, + 1); + } + + smapGenerator.addStratum(smapStratum, false); + + testStratumData.put(stratumName, locationsData); + } + + savePathcedClassFile(className, smapGenerator, smapFileName); + + addJavaLocations(testStratumData, true); + + return testStratumData; + } + + // single input line is mapped to two output lines + protected Map prepareDefaultPatchedClassFile_Type3(String className, int testStratumCount, + boolean setJavaStratumDefault) { + /* + * "Java" "TestStratum" + * + * + * 32 --> 1001, source1 + * 34 --> 1002, source1 + * 36 --> 1003, source1 + * 38 --> 1004, source1 + * + * sde_testMethod1 + * 43 --> 1101, source1 + * 45 --> 1102, source1 + * 47 --> 1103, source1 + * 49 --> 1104, source1 + * + * sde_testMethod2 + * 54 --> 1201, source1 + * 56 --> 1202, source1 + * 58 --> 1203, source1 + * 60 --> 1204, source1 + */ + + Map testStratumData = new TreeMap(); + + String smapFileName = "TestSMAP.smap"; + SmapGenerator smapGenerator = new SmapGenerator(); + + for (int i = 0; i < testStratumCount; i++) { + String stratumName = testStratumName + (i + 1); + LocationsData locationsData = new LocationsData(stratumName); + + String sourceName = testStratumSourceName + (i + 1); + String sourcePath = testStratumSourcePath + (i + 1); + locationsData.paths.add(sourcePath); + + SmapStratum smapStratum = new SmapStratum(stratumName); + + List sourceLocations = new ArrayList(); + + int baseLineNumber = 1000 * (i + 1); + + for (int j = 0; j < 4; j++) { + sourceLocations.add(new DebugLocation(sourceName, sourcePath, + "", baseLineNumber + j, INIT_LINE + j * 2)); + sourceLocations.add(new DebugLocation(sourceName, sourcePath, + "sde_testMethod1", baseLineNumber + 100 + j, METHOD1_LINE + j * 2)); + sourceLocations.add(new DebugLocation(sourceName, sourcePath, + "sde_testMethod2", baseLineNumber + 200 + j, METHOD2_LINE + j * 2)); + } + + locationsData.allLocations.addAll(sourceLocations); + locationsData.sourceLocations.put(sourceName, sourceLocations); + + testStratumData.put(stratumName, locationsData); + + smapStratum.addFile(sourceName, sourcePath); + + for (DebugLocation debugLocation : locationsData.allLocations) { + smapStratum.addLineData(debugLocation.inputLine, sourceName, 1, debugLocation.outputLine, 1); + } + + // if setJavaStratumDefault == false do first stratum default + if (!setJavaStratumDefault && (i == 0)) { + locationsData.isDefault = true; + smapGenerator.addStratum(smapStratum, true); + } else + smapGenerator.addStratum(smapStratum, false); + } + + savePathcedClassFile(className, smapGenerator, smapFileName); + + addJavaLocations(testStratumData, setJavaStratumDefault); + + return testStratumData; + } + + // 3 different test stratums define disjoint locations sets + protected Map prepareDefaultPatchedClassFile_Type4(String className) { + /* + * "Java" "TestStratum1" "TestStratum2" "TestStratum3" + * + * + * 32 --> 1000 + * ... + * ... + * 39 --> 1007 + * + * sde_testMethod1 + * 43 --> 1100 + * ... + * ... + * 50 --> 1107 + * + * sde_testMethod2 + * 54 --> 1200 + * ... + * ... + * 61 --> 1207 + */ + Map testStratumData = new TreeMap(); + + String smapFileName = "TestSMAP.smap"; + + SmapGenerator smapGenerator = new SmapGenerator(); + + String stratumName = testStratumName + "1"; + LocationsData locationsData = new LocationsData(stratumName); + List sourceLocations = new ArrayList(); + String methodName = ""; + for (int i = 0; i < 8; i++) { + sourceLocations.add(new DebugLocation( + testStratumSourceName, testStratumSourcePath, methodName, + 1000 + i, INIT_LINE + i)); + } + locationsData.allLocations.addAll(sourceLocations); + locationsData.sourceLocations.put(testStratumSourceName, sourceLocations); + testStratumData.put(stratumName, locationsData); + + stratumName = testStratumName + "2"; + locationsData = new LocationsData(stratumName); + sourceLocations = new ArrayList(); + methodName = "sde_testMethod1"; + for (int i = 0; i < 8; i++) { + sourceLocations.add(new DebugLocation( + testStratumSourceName, testStratumSourcePath, methodName, + 1100 + i, METHOD1_LINE + i)); + } + locationsData.allLocations.addAll(sourceLocations); + locationsData.sourceLocations.put(testStratumSourceName, sourceLocations); + testStratumData.put(stratumName, locationsData); + + stratumName = testStratumName + "3"; + locationsData = new LocationsData(stratumName); + sourceLocations = new ArrayList(); + methodName = "sde_testMethod2"; + for (int i = 0; i < 8; i++) { + sourceLocations.add(new DebugLocation(testStratumSourceName, testStratumSourcePath, + methodName, 1200 + i, METHOD2_LINE + i)); + } + locationsData.allLocations.addAll(sourceLocations); + locationsData.sourceLocations.put(testStratumSourceName, sourceLocations); + testStratumData.put(stratumName, locationsData); + + for (String stratum : testStratumData.keySet()) { + SmapStratum smapStratum = new SmapStratum(stratum); + smapStratum.addFile(testStratumSourceName, testStratumSourcePath); + + for (DebugLocation debugLocation : testStratumData.get(stratum).allLocations) + smapStratum.addLineData( + debugLocation.inputLine, + debugLocation.sourceName, + 1, + debugLocation.outputLine, + 1); + + smapGenerator.addStratum(smapStratum, false); + } + + savePathcedClassFile(className, smapGenerator, smapFileName); + + return testStratumData; + } + + // single input line is mapped to the single output line, test stratum has 3 + // sources, + // lines in each method has same numbers, each method has locations in 3 + // sources + protected Map prepareDefaultPatchedClassFile_Type5(String className, int testStratumCount) { + /* + * "Java" "TestStratum" + * + * + * 32 --> 1000, source1, path1 + * 33 --> 1000, source2, path2 + * 34 --> 1000, source3, path3 + * ... + * ... + * + * sde_testMethod1 + * 43 --> 1100, source1, path1 + * 44 --> 1100, source2, path2 + * 45 --> 1100, source3, path3 + * ... + * ... + * + * sde_testMethod2 + * 54 --> 1200, source1, path1 + * 55 --> 1200, source2, path2 + * 56 --> 1200, source3, path3 + * ... + * ... + */ + + Map testStratumData = new TreeMap(); + + String smapFileName = "TestSMAP.smap"; + SmapGenerator smapGenerator = new SmapGenerator(); + + for (int i = 0; i < testStratumCount; i++) { + String stratumName = testStratumName + (i + 1); + SmapStratum smapStratum = new SmapStratum(stratumName); + + LocationsData locationsData = new LocationsData(stratumName); + + String sourceName1 = testStratumSourceName + (i + 1) + "_1"; + String sourcePath1 = testStratumSourcePath + (i + 1) + "_1"; + locationsData.paths.add(sourcePath1); + smapStratum.addFile(sourceName1, sourcePath1); + + String sourceName2 = testStratumSourceName + (i + 1) + "_2"; + String sourcePath2 = testStratumSourcePath + (i + 1) + "_2"; + locationsData.paths.add(sourcePath2); + smapStratum.addFile(sourceName2, sourcePath2); + + String sourceName3 = testStratumSourceName + (i + 1) + "_3"; + String sourcePath3 = testStratumSourcePath + (i + 1) + "_3"; + locationsData.paths.add(sourcePath3); + smapStratum.addFile(sourceName3, sourcePath3); + + List source1Locations = new ArrayList(); + List source2Locations = new ArrayList(); + List source3Locations = new ArrayList(); + + for (int j = 0; j < 8; j++) { + if (j % 3 == 0) { + source1Locations.add(new DebugLocation(sourceName1, sourcePath1, + "", 1000, INIT_LINE + j)); + source1Locations.add(new DebugLocation(sourceName1, sourcePath1, + "sde_testMethod1", 1100, METHOD1_LINE + j)); + source1Locations.add(new DebugLocation(sourceName1, sourcePath1, + "sde_testMethod2", 1200, METHOD2_LINE + j)); + } else if (j % 3 == 1) { + source2Locations.add(new DebugLocation(sourceName2, sourcePath2, + "", 1000, INIT_LINE + j)); + source2Locations.add(new DebugLocation(sourceName2, sourcePath2, + "sde_testMethod1", 1100, METHOD1_LINE + j)); + source2Locations.add(new DebugLocation(sourceName2, sourcePath2, + "sde_testMethod2", 1200, METHOD2_LINE + j)); + } else { + source3Locations.add(new DebugLocation(sourceName3, sourcePath3, + "", 1000, INIT_LINE + j)); + source3Locations.add(new DebugLocation(sourceName3, sourcePath3, + "sde_testMethod1", 1100, METHOD1_LINE + j)); + source3Locations.add(new DebugLocation(sourceName3, sourcePath3, + "sde_testMethod2", 1200, METHOD2_LINE + j)); + } + } + + locationsData.sourceLocations.put(sourceName1, source1Locations); + locationsData.sourceLocations.put(sourceName2, source2Locations); + locationsData.sourceLocations.put(sourceName3, source3Locations); + + locationsData.allLocations.addAll(source1Locations); + locationsData.allLocations.addAll(source2Locations); + locationsData.allLocations.addAll(source3Locations); + + for (DebugLocation debugLocation : locationsData.allLocations) { + smapStratum.addLineData( + debugLocation.inputLine, + debugLocation.sourceName, + 1, + debugLocation.outputLine, + 1); + } + + smapGenerator.addStratum(smapStratum, false); + + testStratumData.put(stratumName, locationsData); + } + + savePathcedClassFile(className, smapGenerator, smapFileName); + + return testStratumData; + } + + public static File copyFile(File srcFile, String newFileName) throws IOException { + FileChannel inChannel = new FileInputStream(srcFile).getChannel(); + + File newFile = new File(newFileName); + newFile.createNewFile(); + FileChannel outChannel = new FileOutputStream(newFile).getChannel(); + + outChannel.transferFrom(inChannel, 0, inChannel.size()); + + outChannel.close(); + inChannel.close(); + + return newFile; + } + + // find all locations of method with given name + // (used to check result of 'Method.allLineLocations()') + static protected List locationsOfMethod(List debugLocations, String methodName) { + List result = new ArrayList(); + + for (DebugLocation debugLocation : debugLocations) { + if (debugLocation.methodName.equals(methodName)) + result.add(debugLocation); + } + + return result; + } + + // find all locations for given line and source name + // (used to check result of 'Method.locationsOfLine()' and + // 'ReferenceType.locationsOfLine()') + static protected List locationsOfLine(List debugLocations, String sourceName, + int lineNumber) { + List result = new ArrayList(); + + for (DebugLocation debugLocation : debugLocations) { + if (debugLocation.isConform(sourceName, lineNumber)) + result.add(debugLocation); + } + + return result; + } + + // find locations unique by line number and source name + // (used in 'check_ReferenceType_locationsOfLine' and + // 'check_Method_locationsOfLine' to find all line numbers available for + // ReferenceType or Method) + static protected Set allUniqueLocations(List debugLocations) { + Set result = new TreeSet(); + + for (DebugLocation debugLocation : debugLocations) { + if (!result.contains(debugLocation)) { + result.add(debugLocation); + } + } + + return result; + } + + // check is list of Locations contains only expected locations + protected void compareLocations(List locations, List expectedLocations, String stratum) { + boolean success = true; + + List tempLocations = new LinkedList(locations); + + List tempExpectedLocations = new LinkedList(expectedLocations); + + for(Iterator locationsIterator = tempLocations.iterator(); locationsIterator.hasNext();) { + boolean isExpected = false; + Location location = locationsIterator.next(); + + for(Iterator expectedLocationsIterator = tempExpectedLocations.iterator(); expectedLocationsIterator.hasNext();) { + DebugLocation expectedLocation = expectedLocationsIterator.next(); + if (expectedLocation.compare(location, stratum)) { + isExpected = true; + locationsIterator.remove(); + expectedLocationsIterator.remove(); + break; + } + } + if (!isExpected) { + success = false; + log.complain("Location " + location + " were not found in expected locations"); + } + } + + if (tempLocations.size() != 0) { + success = false; + setSuccess(false); + log.complain("Not all locations were found in expected"); + } + + if (tempExpectedLocations.size() != 0) { + success = false; + setSuccess(false); + log.complain("Following expected locations were not found in received"); + for (DebugLocation expectedLocation : tempExpectedLocations) { + log.complain(expectedLocation.toString()); + } + } + + if (!success) { + setSuccess(false); + log.complain("Expected and actual locations differ"); + + log.complain("Actual locations: "); + for (Location location : locations) { + log.complain(locationToString(location, stratum)); + } + + log.complain("Expected locations: "); + for (DebugLocation expectedLocation : expectedLocations) { + log.complain(expectedLocation.toString()); + } + } + } + + // test all SDE related methods of ReferenceType + protected void checkReferenceType(String stratum, ReferenceType referenceType, List expectedSourceNames, + List expectedSourcePaths, List expectedLocations) { + log.display("Check sourceNames"); + check_ReferenceType_sourceNames(referenceType, stratum, expectedSourceNames); + log.display("Check sourcePaths"); + check_ReferenceType_sourcePaths(referenceType, stratum, expectedSourcePaths); + log.display("Check allLocations"); + check_ReferenceType_allLineLocations(referenceType, stratum, expectedLocations); + log.display("Check locationsOfLine"); + check_ReferenceType_locationsOfLine(referenceType, stratum, false, expectedLocations); + + for (Method method : referenceType.methods()) { + List expectedLocationsOfMethod = locationsOfMethod(expectedLocations, method.name()); + + log.display("Check allLineLocations for method '" + method.name() + "'"); + check_Method_allLineLocations(method, stratum, expectedLocationsOfMethod); + log.display("Check locationsOfLine for method '" + method.name() + "'"); + check_Method_locationsOfLine(method, stratum, false, expectedLocationsOfMethod); + } + } + + // check is 'ReferenceType.sourceNames' returns only expected sources + protected void check_ReferenceType_sourceNames(ReferenceType referenceType, String stratum, + List expectedSourceNames) { + try { + if (stratum == null) { + String sourceName = referenceType.sourceName(); + String expectedSourceName = expectedSourceNames.get(0); + + if (!sourceName.equals(expectedSourceName)) { + setSuccess(false); + log.complain("Unexpected result of ReferenceType.sourceName(): " + sourceName + ", expected is " + + expectedSourceName); + } + } else { + boolean success = true; + + List sourceNames = referenceType.sourceNames(stratum); + + if (!expectedSourceNames.containsAll(sourceNames)) { + success = false; + log.complain("ReferenceType.sourceNames() returns unexpected names"); + } + + if (!sourceNames.containsAll(expectedSourceNames)) { + success = false; + log.complain("Not all expected source names was returned by ReferenceType.sourceNames()"); + } + + if (!success) { + log.complain("Expected source names:"); + for (String name : expectedSourceNames) + log.complain(name); + log.complain("Actual source names:"); + for (String name : sourceNames) + log.complain(name); + } + } + } catch (AbsentInformationException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + } + + // check is 'ReferenceType.sourcePaths' returns only expected paths + protected void check_ReferenceType_sourcePaths(ReferenceType referenceType, String stratum, + List expectedSourcePaths) { + try { + boolean success = true; + + List sourcePaths = referenceType.sourcePaths(stratum); + + if (!expectedSourcePaths.containsAll(sourcePaths)) { + success = false; + log.complain("ReferenceType.sourcePaths() returns unexpected paths"); + } + + if (!sourcePaths.containsAll(expectedSourcePaths)) { + success = false; + log.complain("Not all expected paths was returned by ReferenceType.sourcePaths()"); + } + + if (!success) { + log.complain("Expected paths:"); + for (String path : expectedSourcePaths) + log.complain(path); + log.complain("Actual paths:"); + for (String path : sourcePaths) + log.complain(path); + } + } catch (AbsentInformationException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + } + + // check that method 'ReferenceType.allLineLocations' returns only expected + // locations + protected void check_ReferenceType_allLineLocations(ReferenceType referenceType, String stratum, + List expectedLocations) { + try { + List locations = referenceType.allLineLocations(); + compareLocations(locations, expectedLocations, stratum); + } catch (AbsentInformationException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + + } + + // check that method 'Method.allLineLocations' returns only expected + // locations + protected void check_Method_allLineLocations(Method method, String stratum, + List expectedLocationsOfMethod) { + try { + List methodAllLineLocations = method.allLineLocations(); + compareLocations(methodAllLineLocations, expectedLocationsOfMethod, stratum); + } catch (AbsentInformationException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + } + + // for each line available for method check result of + // 'Method.locationsOfLine' + protected void check_Method_locationsOfLine(Method method, String stratum, boolean allSources, + List expectedLocationsOfMethod) { + try { + for (DebugLocation uniqueLocation : allUniqueLocations(expectedLocationsOfMethod)) { + String sourceName = allSources ? null : uniqueLocation.sourceName; + + List expectedLocationsOfLine = locationsOfLine( + expectedLocationsOfMethod, + sourceName, + uniqueLocation.inputLine); + + List locationsOfLine = (stratum == null) ? method.locationsOfLine(uniqueLocation.inputLine) + : method.locationsOfLine(stratum, sourceName, uniqueLocation.inputLine); + + compareLocations(locationsOfLine, expectedLocationsOfLine, stratum); + } + } catch (AbsentInformationException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + } + + // for each line available for ReferenceType check result of + // 'ReferenceType.locationsOfLine' + protected void check_ReferenceType_locationsOfLine(ReferenceType referenceType, String stratum, boolean allSources, + List expectedLocations) { + try { + for (DebugLocation uniqueLocation : allUniqueLocations(expectedLocations)) { + String sourceName = allSources ? null : uniqueLocation.sourceName; + + List expectedLocationsOfLine = locationsOfLine( + expectedLocations, + sourceName, + uniqueLocation.inputLine); + + List locations = (stratum == null) ? referenceType.locationsOfLine(uniqueLocation.inputLine) + : referenceType.locationsOfLine(stratum, sourceName, uniqueLocation.inputLine); + + compareLocations(locations, expectedLocationsOfLine, stratum); + } + } catch (AbsentInformationException e) { + setSuccess(false); + log.complain("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + + } + + // check that method 'ReferenceType.availableStrata' returns only expected + // stratums + protected void check_ReferenceType_availableStrata(ReferenceType referenceType, List expectedStrata) { + boolean success = true; + + List strata = referenceType.availableStrata(); + + if (!expectedStrata.containsAll(strata)) { + success = false; + log.complain("ReferenceType.availableStrata() returns unexpected values"); + } + + if (!strata.containsAll(expectedStrata)) { + success = false; + log.complain("Not all expected stratums was returned by ReferenceType.availableStrata()"); + } + + if (!success) { + log.complain("Expected stratums:"); + for (String name : expectedStrata) + log.complain(name); + log.complain("Actual stratums:"); + for (String name : strata) + log.complain(name); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapGenerator.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapGenerator.java new file mode 100644 index 00000000000..5686e8f0d7b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapGenerator.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi.sde; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a source map (SMAP), which serves to associate lines + * of the input source to lines in the generated output source in the + * final .class file, according to the JSR-045 spec. + */ +public class SmapGenerator { + + //********************************************************************* + // Overview + + /* + * The SMAP syntax is reasonably straightforward. The purpose of this + * class is currently twofold: + * - to provide a simple but low-level Java interface to build + * a logical SMAP + * - to serialize this logical SMAP for eventual inclusion directly + * into a .class file. + */ + + + //********************************************************************* + // Private state + + private String outputFileName; + private String defaultStratum = "Java"; + private List strata = new ArrayList(); + private List embedded = new ArrayList(); + private boolean doEmbedded = true; + + //********************************************************************* + // Methods for adding mapping data + + /** + * Sets the filename (without path information) for the generated + * source file. E.g., "foo$jsp.java". + */ + public synchronized void setOutputFileName(String x) { + outputFileName = x; + } + + /** + * Adds the given SmapStratum object, representing a Stratum with + * logically associated FileSection and LineSection blocks, to + * the current SmapGenerator. If default is true, this + * stratum is made the default stratum, overriding any previously + * set default. + * + * @param stratum the SmapStratum object to add + * @param defaultStratum if true, this SmapStratum is considered + * to represent the default SMAP stratum unless + * overwritten + */ + public synchronized void addStratum(SmapStratum stratum, + boolean defaultStratum) { + strata.add(stratum); + if (defaultStratum) + this.defaultStratum = stratum.getStratumName(); + } + + /** + * Adds the given string as an embedded SMAP with the given stratum name. + * + * @param smap the SMAP to embed + * @param stratumName the name of the stratum output by the compilation + * that produced the smap to be embedded + */ + public synchronized void addSmap(String smap, String stratumName) { + embedded.add("*O " + stratumName + "\n" + + smap + + "*C " + stratumName + "\n"); + } + + /** + * Instructs the SmapGenerator whether to actually print any embedded + * SMAPs or not. Intended for situations without an SMAP resolver. + * + * @param status If false, ignore any embedded SMAPs. + */ + public void setDoEmbedded(boolean status) { + doEmbedded = status; + } + + public File saveToFile(String fileName) + throws IOException + { + File file = new File(fileName); + + file.createNewFile(); + + FileOutputStream outStream = new FileOutputStream(file); + outStream.write(getString().getBytes()); + outStream.close(); + + return file; + } + + //********************************************************************* + // Methods for serializing the logical SMAP + + public synchronized String getString() { + // check state and initialize buffer + if (outputFileName == null) + throw new IllegalStateException(); + StringBuffer out = new StringBuffer(); + + // start the SMAP + out.append("SMAP\n"); + out.append(outputFileName + '\n'); + out.append(defaultStratum + '\n'); + + // include embedded SMAPs + if (doEmbedded) { + int nEmbedded = embedded.size(); + for (int i = 0; i < nEmbedded; i++) { + out.append(embedded.get(i)); + } + } + + // print our StratumSections, FileSections, and LineSections + int nStrata = strata.size(); + for (int i = 0; i < nStrata; i++) { + SmapStratum s = (SmapStratum) strata.get(i); + out.append(s.getString()); + } + + // end the SMAP + out.append("*E\n"); + + return out.toString(); + } + + public String toString() { return getString(); } + + //********************************************************************* + // For testing (and as an example of use)... + + public static void main(String args[]) { + SmapGenerator g = new SmapGenerator(); + g.setOutputFileName("foo.java"); + SmapStratum s = new SmapStratum("JSP"); + s.addFile("foo.jsp"); + s.addFile("bar.jsp", "/foo/foo/bar.jsp"); + s.addLineData(1, "foo.jsp", 1, 1, 1); + s.addLineData(2, "foo.jsp", 1, 6, 1); + s.addLineData(3, "foo.jsp", 2, 10, 5); + s.addLineData(20, "bar.jsp", 1, 30, 1); + g.addStratum(s, true); + System.out.print(g); + + System.out.println("---"); + + SmapGenerator embedded = new SmapGenerator(); + embedded.setOutputFileName("blargh.tier2"); + s = new SmapStratum("Tier2"); + s.addFile("1.tier2"); + s.addLineData(1, "1.tier2", 1, 1, 1); + embedded.addStratum(s, true); + g.addSmap(embedded.toString(), "JSP"); + System.out.println(g); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapStratum.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapStratum.java new file mode 100644 index 00000000000..c142c5cd720 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapStratum.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jdi.sde; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents the line and file mappings associated with a JSR-045 + * "stratum". + */ +public class SmapStratum +{ + + //********************************************************************* + // Class for storing LineInfo data + + /** + * Represents a single LineSection in an SMAP, associated with + * a particular stratum. + */ + public static class LineInfo { + private int inputStartLine = -1; + private int outputStartLine = -1; + private int lineFileID = 0; + private int inputLineCount = 1; + private int outputLineIncrement = 1; + private boolean lineFileIDSet = false; + + /** Sets InputStartLine. */ + public void setInputStartLine(int inputStartLine) { + if (inputStartLine < 0) + throw new IllegalArgumentException("" + inputStartLine); + this.inputStartLine = inputStartLine; + } + + /** Sets OutputStartLine. */ + public void setOutputStartLine(int outputStartLine) { + if (outputStartLine < 0) + throw new IllegalArgumentException("" + outputStartLine); + this.outputStartLine = outputStartLine; + } + + /** + * Sets lineFileID. Should be called only when different from + * that of prior LineInfo object (in any given context) or 0 + * if the current LineInfo has no (logical) predecessor. + * LineInfo will print this file number no matter what. + */ + public void setLineFileID(int lineFileID) { + if (lineFileID < 0) + throw new IllegalArgumentException("" + lineFileID); + this.lineFileID = lineFileID; + this.lineFileIDSet = true; + } + + /** Sets InputLineCount. */ + public void setInputLineCount(int inputLineCount) { + if (inputLineCount < 0) + throw new IllegalArgumentException("" + inputLineCount); + this.inputLineCount = inputLineCount; + } + + /** Sets OutputLineIncrement. */ + public void setOutputLineIncrement(int outputLineIncrement) { + if (outputLineIncrement < 0) + throw new IllegalArgumentException("" + outputLineIncrement); + this.outputLineIncrement = outputLineIncrement; + } + + /** + * Retrieves the current LineInfo as a String, print all values + * only when appropriate (but LineInfoID if and only if it's been + * specified, as its necessity is sensitive to context). + */ + public String getString() { + if (inputStartLine == -1 || outputStartLine == -1) + throw new IllegalStateException(); + StringBuffer out = new StringBuffer(); + out.append(inputStartLine); + if (lineFileIDSet) + out.append("#" + lineFileID); + if (inputLineCount != 1) + out.append("," + inputLineCount); + out.append(":" + outputStartLine); + if (outputLineIncrement != 1) + out.append("," + outputLineIncrement); + out.append('\n'); + return out.toString(); + } + + public String toString() { + return getString(); + } + } + + //********************************************************************* + // Private state + + private String stratumName; + private List fileNameList; + private List filePathList; + private List lineData; + private int lastFileID; + + //********************************************************************* + // Constructor + + /** + * Constructs a new SmapStratum object for the given stratum name + * (e.g., JSP). + * + * @param stratumName the name of the stratum (e.g., JSP) + */ + public SmapStratum(String stratumName) { + this.stratumName = stratumName; + fileNameList = new ArrayList(); + filePathList = new ArrayList(); + lineData = new ArrayList(); + lastFileID = 0; + } + + //********************************************************************* + // Methods to add mapping information + + /** + * Adds record of a new file, by filename. + * + * @param filename the filename to add, unqualified by path. + */ + public void addFile(String filename) { + addFile(filename, filename); + } + + /** + * Adds record of a new file, by filename and path. The path + * may be relative to a source compilation path. + * + * @param filename the filename to add, unqualified by path + * @param filePath the path for the filename, potentially relative + * to a source compilation path + */ + public void addFile(String filename, String filePath) { + int pathIndex = filePathList.indexOf(filePath); + if (pathIndex == -1) { + fileNameList.add(filename); + filePathList.add(filePath); + } + } + + /** + * Adds complete information about a simple line mapping. Specify + * all the fields in this method; the back-end machinery takes care + * of printing only those that are necessary in the final SMAP. + * (My view is that fields are optional primarily for spatial efficiency, + * not for programmer convenience. Could always add utility methods + * later.) + * + * @param inputStartLine starting line in the source file + * (SMAP InputStartLine) + * @param inputFileName the filepath (or name) from which the input comes + * (yields SMAP LineFileID) Use unqualified names + * carefully, and only when they uniquely identify a file. + * @param inputLineCount the number of lines in the input to map + * (SMAP LineFileCount) + * @param outputStartLine starting line in the output file + * (SMAP OutputStartLine) + * @param outputLineIncrement number of output lines to map to each + * input line (SMAP OutputLineIncrement). Given the + * fact that the name starts with "output", I continuously have + * the subconscious urge to call this field + * OutputLineExcrement. + */ + public void addLineData( + int inputStartLine, + String inputFileName, + int inputLineCount, + int outputStartLine, + int outputLineIncrement) { + // check the input - what are you doing here?? + int fileIndex = fileNameList.indexOf(inputFileName); + if (fileIndex == -1) // still + throw new IllegalArgumentException( + "inputFileName: " + inputFileName); + + //Jasper incorrectly SMAPs certain Nodes, giving them an + //outputStartLine of 0. This can cause a fatal error in + //optimizeLineSection, making it impossible for Jasper to + //compile the JSP. Until we can fix the underlying + //SMAPping problem, we simply ignore the flawed SMAP entries. + if (outputStartLine == 0) + return; + + // build the LineInfo + LineInfo li = new LineInfo(); + li.setInputStartLine(inputStartLine); + li.setInputLineCount(inputLineCount); + li.setOutputStartLine(outputStartLine); + li.setOutputLineIncrement(outputLineIncrement); + if (fileIndex != lastFileID) + li.setLineFileID(fileIndex); + lastFileID = fileIndex; + + // save it + lineData.add(li); + } + + //********************************************************************* + // Methods to retrieve information + + /** + * Returns the name of the stratum. + */ + public String getStratumName() { + return stratumName; + } + + /** + * Returns the given stratum as a String: a StratumSection, + * followed by at least one FileSection and at least one LineSection. + */ + public String getString() { + // check state and initialize buffer + if (fileNameList.size() == 0 || lineData.size() == 0) + return null; + + StringBuffer out = new StringBuffer(); + + // print StratumSection + out.append("*S " + stratumName + "\n"); + + // print FileSection + out.append("*F\n"); + int bound = fileNameList.size(); + for (int i = 0; i < bound; i++) { + if (filePathList.get(i) != null) { + out.append("+ " + i + " " + fileNameList.get(i) + "\n"); + // Source paths must be relative, not absolute, so we + // remove the leading "/", if one exists. + String filePath = (String)filePathList.get(i); + if (filePath.startsWith("/")) { + filePath = filePath.substring(1); + } + out.append(filePath + "\n"); + } else { + out.append(i + " " + fileNameList.get(i) + "\n"); + } + } + + // print LineSection + out.append("*L\n"); + bound = lineData.size(); + for (int i = 0; i < bound; i++) { + LineInfo li = (LineInfo)lineData.get(i); + out.append(li.getString()); + } + + return out.toString(); + } + + public String toString() { + return getString(); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/TestClass1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/TestClass1.java new file mode 100644 index 00000000000..8a15d285bb3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/TestClass1.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// THIS TEST IS LINE NUMBER SENSITIVE + +package nsk.share.jdi.sde; + +// Class contains 3 methods with several locations, do not edit this file because of line numbers are hardcoded in tests +public class TestClass1 { + public TestClass1() + { + super(); // SDEDebugger.INIT_LINE + int i = 0; + i++; + i++; + i++; + i++; + i++; + } + + public void sde_testMethod1() + { + int i = 0; // SDEDebugger.METHOD1_LINE + i++; + i++; + i++; + i++; + i++; + i++; + } + + public void sde_testMethod2() + { + int i = 0; // SDEDebugger.METHOD2_LINE + i++; + i++; + i++; + i++; + i++; + i++; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/JNIreferences.c b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/JNIreferences.c new file mode 100644 index 00000000000..e508c7dda6e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/JNIreferences.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "jni.h" +#include +#include "nsk_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_PTR + +#ifdef __cplusplus +#define JNI_ENV_ARG_2(x, y) y +#define JNI_ENV_ARG_3(x, y, z) y, z +#define JNI_ENV_ARG_4(x, y, z, a) y, z, a +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG_2(x,y) x, y +#define JNI_ENV_ARG_3(x, y, z) x, y, z +#define JNI_ENV_ARG_4(x, y, z, a) x, y, z, a +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + +static jobject* globalReferences = NULL; +static jweak* weakReferences = NULL; + +JNIEXPORT jint JNICALL +Java_nsk_share_ReferringObject_createJNIGlobalReferenceNative(JNIEnv *env, + jobject thisObject, jobject object, jint maxJNIGlobalReferences) +{ + jint i; + jint result = -1; + + if(globalReferences == NULL) + { + globalReferences = (jobject*)malloc(sizeof(jobject) * maxJNIGlobalReferences); + + if(globalReferences == NULL) + { + NSK_COMPLAIN0("malloc return NULL\n"); + return -1; + } + + for(i = 0; i < maxJNIGlobalReferences; i++) + { + globalReferences[i] = NULL; + } + } + + for(i = 0; i < maxJNIGlobalReferences; i++) + { + jobject reference = globalReferences[i]; + + if(reference == NULL) + { + reference = JNI_ENV_PTR(env)->NewGlobalRef(JNI_ENV_ARG_2(env, object)); + + if(reference == NULL) + { + NSK_COMPLAIN0("NewGlobalRef return NULL\n"); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "NewGlobalRef return NULL")); + } + + globalReferences[i] = reference; + + result = i; + + break; + } + } + + return result; +} + +JNIEXPORT void JNICALL +Java_nsk_share_ReferringObject_deleteJNIGlobalReferenceNative(JNIEnv *env, + jobject thisObject, jint index) +{ + jobject reference = globalReferences[index]; + + if(reference == NULL) + { + NSK_COMPLAIN1("globalReferences[%d] = NULL, possible wrong index is passed\n", index); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestBug")), "Requested globalReferences[] element is NULL, possible wrong index is passed")); + } + + JNI_ENV_PTR(env)->DeleteGlobalRef(JNI_ENV_ARG_2(env, reference)); + + globalReferences[index] = NULL; +} + + +JNIEXPORT void JNICALL +Java_nsk_share_ReferringObject_createJNILocalReferenceNative(JNIEnv *env, + jobject thisObject, jobject object, jobject createWicket, jobject deleteWicket) +{ + jobject reference = JNI_ENV_PTR(env)->NewLocalRef(JNI_ENV_ARG_2(env, object)); + jclass klass; + + if(reference == NULL) + { + NSK_COMPLAIN0("NewLocalRef return NULL\n"); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "NewLocalRef return NULL")); + } + + klass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, createWicket)); + + // notify another thread that JNI local reference has been created + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, createWicket, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, klass, "unlock", "()V")))); + + // wait till JNI local reference can be released (it will heppen then we will leave the method) + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, deleteWicket, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, klass, "waitFor", "()V")))); +} + +JNIEXPORT jint JNICALL +Java_nsk_share_ReferringObject_createJNIWeakReferenceNative(JNIEnv *env, + jobject thisObject, jobject object, jint maxJNIWeakReferences) +{ + jint i; + jint result = -1; + + if(weakReferences == NULL) + { + weakReferences = (jweak*)malloc(sizeof(jweak) * maxJNIWeakReferences); + + if(weakReferences == NULL) + { + NSK_COMPLAIN0("malloc return NULL\n"); + + return -1; + } + + for(i = 0; i < maxJNIWeakReferences; i++) + { + weakReferences[i] = NULL; + } + } + + for(i = 0; i < maxJNIWeakReferences; i++) + { + jobject reference = weakReferences[i]; + + if(reference == NULL) + { + reference = JNI_ENV_PTR(env)->NewWeakGlobalRef(JNI_ENV_ARG_2(env, object)); + + if(reference == NULL) + { + NSK_COMPLAIN0("NewWeakGlobalRef return NULL\n"); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "NewWeakGlobalRef return NULL")); + } + + weakReferences[i] = reference; + + result = i; + + break; + } + } + + return result; +} + +JNIEXPORT void JNICALL +Java_nsk_share_ReferringObject_deleteJNIWeakReferenceNative(JNIEnv *env, + jobject thisObject, jint index) +{ + jweak reference = weakReferences[index]; + + if(reference == NULL) + { + NSK_COMPLAIN1("weakReferences[%d] = NULL, possible wrong index is passed\n", index); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestBug")), "Requested weakReferences[] element is NULL, possible wrong index is passed")); + } + + if(JNI_ENV_PTR(env)->IsSameObject(JNI_ENV_ARG_3(env, reference, NULL)) == JNI_TRUE) + { + NSK_COMPLAIN0("TEST BUG: Weak reference was collected\n"); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestBug")), "TEST BUG: Weak reference was collected")); + } + + JNI_ENV_PTR(env)->DeleteWeakGlobalRef(JNI_ENV_ARG_2(env, reference)); + + weakReferences[index] = NULL; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/README b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/README new file mode 100644 index 00000000000..b55331b09de --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/README @@ -0,0 +1,61 @@ +Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This code is free software; you can redistribute it and\\\/or modify it +under the terms of the GNU General Public License version 2 only, as +published by the Free Software Foundation. +This code is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. + +--------------------------------------------------------------------------------- + +This directory contains source files of testbase_nsk JNI framework, +which provides support for JNI tests and accessing JNI environment. + + Source files: + jni_tools.h + jni_tools.c + + Naming conventions: + macroses: NSK_JNI_* + functions: nsk_JNI_* + +--------------------------------------------------------------------------------- + +jni_tools.h + +Provides functions and macroses for invocation of JNI functions +and checking JNI errors and pending exceptions: + + NSK_JNI_VERIFY(jni, action) + NSK_JNI_VERIFY_NEGATIVE(jni, action) + +Typical example of usage of NSK_JNI_VERIFY and NSK_CPP_STUB macroses +for invokation of JNI functions: + + // jni->FindClass(jni, class_name) + if (!NSK_JNI_VERIFY(jni, + NSK_CPP_STUB2(FindClass, jni, class_name) != NULL)) { + return JNI_ERR; + } + +or with saving obtained data: + + // cls = jni->FindClass(jni, class_name) + if (!NSK_JNI_VERIFY(jni, (cls = + NSK_CPP_STUB2(FindClass, jni, class_name)) != NULL)) { + return JNI_ERR; + } + +--------------------------------------------------------------------------------- diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.c b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.c new file mode 100644 index 00000000000..71a2f83ca9e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include + +/*************************************************************/ +#if (defined(WIN32) || defined(_WIN32)) +#include +#else +#include +#include +#endif +/*************************************************************/ + +#include "jni.h" + +/*************************************************************/ + +#include "nsk_tools.h" +#include "jni_tools.h" + +/*************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************/ + +int nsk_jni_check_exception(JNIEnv* jni, const char file[], int line) +{ + jthrowable throwable; + + NSK_TRACE(throwable = NSK_CPP_STUB1(ExceptionOccurred, jni)); + if (throwable != NULL) { + nsk_lcomplain(file, line, "Exception in JNI call (cleared):\n"); + NSK_TRACE(NSK_CPP_STUB1(ExceptionDescribe, jni)); + NSK_TRACE(NSK_CPP_STUB1(ExceptionClear, jni)); + return NSK_TRUE; + } + return NSK_FALSE; +} + +int nsk_jni_lverify(int positive, JNIEnv* jni, int status, + const char file[], int line, const char format[], ...) +{ + int failure=0; + int negative = !positive; + va_list ap; + va_start(ap,format); + + nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap); + if (status == negative) { + nsk_lvcomplain(file,line,format,ap); + nsk_printf("# verified JNI assertion is FALSE\n"); + failure=1; + } + + failure = nsk_jni_check_exception(jni, file, line) || failure; + + va_end(ap); + return !failure; +} + +int nsk_jni_lverify_void(JNIEnv* jni, const char file[], int line, + const char format[], ...) +{ + int failure=0; + va_list ap; + va_start(ap,format); + + nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap); + failure = nsk_jni_check_exception(jni, file, line); + + if (failure) + nsk_lvcomplain(file,line,format,ap); + + va_end(ap); + return !failure; +} + +char *jlong_to_string(jlong value, char *string) { + char buffer[32]; + char *pbuf, *pstr; + + pstr = string; + if (value == 0) { + *pstr++ = '0'; + } else { + if (value < 0) { + *pstr++ = '-'; + value = -value; + } + pbuf = buffer; + while (value != 0) { + *pbuf++ = '0' + (char)(value % 10); + value = value / 10; + } + while (pbuf != buffer) { + *pstr++ = *--pbuf; + } + } + *pstr = '\0'; + + return string; +} + +char *julong_to_string(julong value, char *string) { + char buffer[32]; + char *pbuf, *pstr; + + pstr = string; + if (value == 0) { + *pstr++ = '0'; + } else { + pbuf = buffer; + while (value != 0) { + *pbuf++ = '0' + (char)(value % 10); + value = value / 10; + } + while (pbuf != buffer) { + *pstr++ = *--pbuf; + } + } + *pstr = '\0'; + + return string; +} + +void mssleep(long millis) { +#if (defined(WIN32) || defined(_WIN32)) + Sleep(millis); +#else + /* Using select for portable sleep */ + /* Not using usleep because of it's possible interaction with SIGALRM */ + struct timeval timeout; + timeout.tv_sec = millis / 1000; + timeout.tv_usec = (millis % 1000) * 1000; + select(0, NULL, NULL, NULL, &timeout); +#endif +} + +void +jni_print_vmargs(JavaVMInitArgs vmargs) +{ + int i = 0; + + printf("JavaVMInitArgs:\n"); + printf(" version = %d\n", vmargs.version); + printf(" ignoreUnrecognized = %d\n", vmargs.ignoreUnrecognized); + + printf(" vmargs.nOptions = %d\n", vmargs.nOptions); + for (i = 0; i < vmargs.nOptions; i++) { + printf(" options[%d].optionString = %s\n", i, vmargs.options[i].optionString); + printf(" options[%d].extraInfo = %p\n", i, vmargs.options[i].extraInfo); + } +} + +JavaVMOption* +jni_create_vmoptions(int size, char *args[], int argsCnt) +{ + int i; + JavaVMOption *options = NULL; + + if (size <= 0) + return options; + + options = (JavaVMOption*)calloc(size, sizeof(JavaVMOption)); + + for (i=0; i + +#else // !_WIN32 + +#include + +#ifdef _LP64 +#define LL "l" +#else +#define LL "ll" +#endif + +#endif // !_WIN32 + +/** + * Additional Java basic types + */ + +#ifdef _WIN32 + typedef unsigned __int64 julong; +#else + typedef unsigned long long julong; +#endif + +/*************************************************************/ + +/** + * Execute action with JNI call, check result for true and + * pending exception and complain error if required. + * Also trace action execution if tracing mode enabled. + */ +#define NSK_JNI_VERIFY(jni, action) \ + (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \ + nsk_jni_lverify(NSK_TRUE,jni,action,__FILE__,__LINE__,"%s\n",#action)) + +/** + * Execute action with JNI call, check result for false and + * pending exception and complain error if required. + * Also trace action execution if tracing mode enabled. + */ +#define NSK_JNI_VERIFY_NEGATIVE(jni,action) \ + (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \ + nsk_jni_lverify(NSK_FALSE,jni,action,__FILE__,__LINE__,"%s\n",#action)) + +/** + * Execute action with JNI call, check result for + * pending exception and complain error if required. + * Also trace action execution if tracing mode enabled. + */ +#define NSK_JNI_VERIFY_VOID(jni,action) \ + (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \ + action, \ + nsk_jni_lverify_void(jni, __FILE__,__LINE__,"%s\n",#action)) + +/*************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************/ + +/** + * If positive, assert status is true; or + * if !positive, assert status is not true. + * Assert means: complain if the assertion is false. + * Return the assertion value, either NSK_TRUE or NSK_FALSE. + * Anyway, trace if "nsk_tools" mode is verbose and + * print information about pending exceptions if status is false. + */ +int nsk_jni_lverify(int positive, JNIEnv* jni, int status, + const char file[], int line, const char format[], ...); + +/** + * If positive, assert status is true; or + * if !positive, assert status is not true. + * Assert means: complain if the assertion is false. + * Return the assertion value, either NSK_TRUE or NSK_FALSE. + * Anyway, trace if "nsk_tools" mode is verbose and + * print information about pending exceptions if status is false. + */ +int nsk_jni_lverify_void(JNIEnv* jni, const char file[], int line, + const char format[], ...); + +/** + * Checks if pending exception exists and then prints error message + * with exception description, clears pending exception amd return 1. + * Otherwise, does noting and returns 0, + */ +int nsk_jni_check_exception(JNIEnv* jni, const char file[], int line); + +/** + * Convert the digits of the given value argument to a null-terminated + * character string and store the result (up to 32 bytes) in string. + * If value is negative, the first character of the stored string is + * the minus sign (-). The function returns a pointer to the begining + * of the result string. + */ +char *jlong_to_string(jlong value, char *string); + +/** + * Convert the digits of the given value argument to a null-terminated + * character string and store the result (up to 32 bytes) in string. + * The function returns a pointer to the begining of the result string. + */ +char *julong_to_string(julong value, char *string); + +/** + * Sleep for given number of milliseconds. + */ +void mssleep(long millis); + +/** + * Create JavaVMOption array of size 'size' and fills + * first argsCnt elements from args[]. + * Callee is responsible to free JavaVMOption*. + * No other memory deallocations are required. + */ +JavaVMOption* jni_create_vmoptions(int size, char *args[], int argsCnt); + +/** + * Print JavaVMInitArgs values to stdout. + */ +void jni_print_vmargs(JavaVMInitArgs vmargs); + +/*************************************************************/ + +#ifdef __cplusplus +} +#endif + +/*************************************************************/ + +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java new file mode 100644 index 00000000000..0668297d211 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// THIS TEST IS LINE NUMBER SENSITIVE + +package nsk.share.jpda; + +import java.io.*; +import java.util.*; +import nsk.share.*; +import nsk.share.test.*; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +/* + * Class can be used as base debuggee class in jdi and jdwp tests. + * Class contains common method for initializing log, pipe, vm, and several common auxiliary methods. Subclass should implement parseCommand() and, if needed, doInit(parse command line parameters) + * !!! Edit carefully, value of 'DEFAULT_BREAKPOINT_LINE' is hardcoded !!! + */ +public class AbstractDebuggeeTest { + protected DebugeeArgumentHandler argHandler; + + protected IOPipe pipe; + + protected Log log; + + protected boolean callExit = true; + + private boolean success = true; + + protected void setSuccess(boolean value) { + success = value; + } + + public boolean getSuccess() { + return success; + } + + public final static int DEFAULT_BREAKPOINT_LINE = 63; + + public final static String DEFAULT_BREAKPOINT_METHOD_NAME = "breakpointMethod"; + + public void breakpointMethod() { + log.display("In breakpoint method: 'AbstractDebuggeeTest.breakpointMethod()'"); // DEFAULT_BREAKPOINT_LINE + } + + protected Map loadedClasses = new TreeMap(); + + public final static String COMMAND_FORCE_BREAKPOINT = "forceBreakpoint"; + + //load class with given name with possibility to unload it + static public final String COMMAND_LOAD_CLASS = "loadClass"; + + // unload class with given name(it is possible for classes loaded via loadTestClass method) + // command:className[:], - one of UNLOAD_RESULT_TRUE or UNLOAD_RESULT_FALSE + static public final String COMMAND_UNLOAD_CLASS = "unloadClass"; + + // Optional arguments of COMMAND_UNLOAD_CLASS + // (is after unloading class should be really unloaded, default value is UNLOAD_RESULT_TRUE) + static public final String UNLOAD_RESULT_TRUE = "unloadResultTrue"; + + static public final String UNLOAD_RESULT_FALSE = "unloadResultFalse"; + + static public final String COMMAND_CREATE_STATETESTTHREAD = "createStateTestThread"; + + static public final String COMMAND_NEXTSTATE_STATETESTTHREAD = "stateTestThreadNextState"; + + //force GC using AbstractDebuggeeTest.eatMemory() + static public final String COMMAND_FORCE_GC = "forceGC"; + // GCcount is used to get information about GC activity during test + static public final String COMMAND_GC_COUNT = "GCcount"; + private int lastGCCount; + + + static public final String stateTestThreadName = "stateTestThread"; + + static public final String stateTestThreadClassName = StateTestThread.class.getName(); + + // path to classes intended for loading/unloading + protected String classpath; + + // classloader loads only test classes from nsk.* + public static class TestClassLoader extends CustomClassLoader { + public Class loadClass(String name) throws ClassNotFoundException { + if (name.startsWith("nsk.")) + return findClass(name); + else + return super.loadClass(name); + } + } + + protected StressOptions stressOptions; + protected Stresser stresser; + + // initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments + // (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options) + // support -testClassPath parameter: path to find classes for custom classloader + protected String[] doInit(String[] args) { + stressOptions = new StressOptions(args); + stresser = new Stresser(stressOptions); + + ArrayList standardArgs = new ArrayList(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-testClassPath") && (i < args.length - 1)) { + classpath = args[i + 1]; + i++; + } else + standardArgs.add(args[i]); + } + + return standardArgs.toArray(new String[] {}); + } + + public void loadTestClass(String className) { + if (classpath == null) { + throw new TestBug("Debuggee requires 'testClassPath' parameter"); + } + + try { + ClassUnloader classUnloader = new ClassUnloader(); + + classUnloader.setClassLoader(new TestClassLoader()); + classUnloader.loadClass(className, classpath); + loadedClasses.put(className, classUnloader); + } catch (ClassNotFoundException e) { + log.complain("Unexpected 'ClassNotFoundException' on loading of the requested class(" + className + ")"); + e.printStackTrace(log.getOutStream()); + throw new TestBug("Unexpected 'ClassNotFoundException' on loading of the requested class(" + className + ")"); + } + } + + public static final int MAX_UNLOAD_ATTEMPS = 5; + + public void unloadTestClass(String className, boolean expectedUnloadingResult) { + ClassUnloader classUnloader = loadedClasses.get(className); + + int unloadAttemps = 0; + + if (classUnloader != null) { + boolean wasUnloaded = false; + + while (!wasUnloaded && (unloadAttemps++ < MAX_UNLOAD_ATTEMPS)) { + wasUnloaded = classUnloader.unloadClass(); + } + + if (wasUnloaded) + loadedClasses.remove(className); + else { + log.display("Class " + className + " was not unloaded"); + } + + if (wasUnloaded != expectedUnloadingResult) { + setSuccess(false); + + if (wasUnloaded) + log.complain("Class " + className + " was unloaded!"); + else + log.complain("Class " + className + " wasn't unloaded!"); + } + } else { + log.complain("Invalid command 'unloadClass' is requested: class " + className + " was not loaded via ClassUnloader"); + throw new TestBug("Invalid command 'unloadClass' is requested: class " + className + " was not loaded via ClassUnloader"); + } + } + + static public void sleep1sec() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + + private StateTestThread stateTestThread; + + public static final String COMMAND_QUIT = "quit"; + + public static final String COMMAND_READY = "ready"; + + private void createStateTestThread() { + if (stateTestThread != null) + throw new TestBug("StateTestThread already created"); + + stateTestThread = new StateTestThread(stateTestThreadName); + } + + private void stateTestThreadNextState() { + if (stateTestThread == null) + throw new TestBug("StateTestThread not created"); + + stateTestThread.nextState(); + } + + public boolean parseCommand(String command) { + try { + StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command)); + tokenizer.whitespaceChars(':', ':'); + tokenizer.wordChars('_', '_'); + tokenizer.wordChars('$', '$'); + tokenizer.wordChars('[', ']'); + + if (command.equals(COMMAND_FORCE_GC)) { + forceGC(); + lastGCCount = getCurrentGCCount(); + return true; + } else if (command.equals(COMMAND_GC_COUNT)) { + pipe.println(COMMAND_GC_COUNT + ":" + (getCurrentGCCount() - lastGCCount)); + return true; + } else if (command.equals(COMMAND_FORCE_BREAKPOINT)) { + breakpointMethod(); + return true; + } else if (command.equals(COMMAND_CREATE_STATETESTTHREAD)) { + createStateTestThread(); + + return true; + } else if (command.equals(COMMAND_NEXTSTATE_STATETESTTHREAD)) { + stateTestThreadNextState(); + + return true; + } else if (command.startsWith(COMMAND_LOAD_CLASS)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String className = tokenizer.sval; + + loadTestClass(className); + + return true; + } else if (command.startsWith(COMMAND_UNLOAD_CLASS)) { + tokenizer.nextToken(); + + if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) + throw new TestBug("Invalid command format: " + command); + + String className = tokenizer.sval; + + boolean expectedUnloadingResult = true; + + if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) { + if (tokenizer.sval.equals(UNLOAD_RESULT_TRUE)) + expectedUnloadingResult = true; + else if (tokenizer.sval.equals(UNLOAD_RESULT_FALSE)) + expectedUnloadingResult = false; + else + throw new TestBug("Invalid command format: " + command); + } + + unloadTestClass(className, expectedUnloadingResult); + + return true; + } + } catch (IOException e) { + throw new TestBug("Invalid command format: " + command); + } + + return false; + } + + protected DebugeeArgumentHandler createArgumentHandler(String args[]) { + return new DebugeeArgumentHandler(args); + } + + protected void init(String args[]) { + argHandler = createArgumentHandler(doInit(args)); + pipe = argHandler.createDebugeeIOPipe(); + log = argHandler.createDebugeeLog(); + lastGCCount = getCurrentGCCount(); + } + + public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String[] args, boolean callExit) { + this.argHandler = argHandler; + this.log = log; + this.pipe = pipe; + this.callExit = callExit; + doInit(args); + } + + public void doTest(String args[]) { + init(args); + doTest(); + } + + public void doTest() { + do { + log.display("Debuggee " + getClass().getName() + " : sending the command: " + AbstractDebuggeeTest.COMMAND_READY); + pipe.println(AbstractDebuggeeTest.COMMAND_READY); + + String command = pipe.readln(); + log.display("Debuggee: received the command: " + command); + + if (command.equals(AbstractDebuggeeTest.COMMAND_QUIT)) { + break; + } else { + try { + if (!parseCommand(command)) { + log.complain("TEST BUG: unknown debugger command: " + command); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } catch (Throwable t) { + log.complain("Unexpected exception in debuggee: " + t); + t.printStackTrace(log.getOutStream()); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + } while (true); + + log.display("Debuggee: exiting"); + + if (callExit) { + if (success) + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED); + else + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + + public static void eatMemory() { + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + int memoryChunk = (int) (maxMemory / 50); + try { + List list = new ArrayList(); + while (true) { + list.add(new byte[memoryChunk]); + } + } catch (OutOfMemoryError e) { + // expected exception + } + } + + public static int getCurrentGCCount() { + int result = 0; + List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + for (GarbageCollectorMXBean bean : gcBeans) { + result += bean.getCollectionCount(); + } + return result; + } + + public void forceGC() { + eatMemory(); + } + + public void voidValueMethod() { + } + + public void unexpectedException(Throwable t) { + setSuccess(false); + t.printStackTrace(log.getOutStream()); + log.complain("Unexpected exception: " + t); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java new file mode 100644 index 00000000000..6ad2150acef --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java @@ -0,0 +1,1888 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jpda; + +import java.io.*; +import java.net.*; +import java.util.*; + +import nsk.share.*; +import nsk.share.jpda.*; + +/** + * BindServer is an utility to perform JPDA tests + * in remote mode across network. + *

      + * This utility should be started on remote host. It listens for connection + * from JPDA tests and launches debuggee VM on this host. + *

      + * BindServer works together with Binder used in + * the tests to incapsulate actions required for launching debuggee VM. + * See ProcessBinder and DebugeeArgumentHandler + * to know how run tests in local or remote mode across network or + * on an single host. + *

      + * BindServer is started on the debuggee host. + * It recognizes following command line options: + *

        + *
      • -bind.file=filename - configuration file + *
      • -verbose - print verbose messages + *
      + *

      + * Only required option is -bind.file, which points to the file + * where pairs of particular pathes are presented as they are seen from + * both hosts along with some other BindServer options. + * See execution.html to read more about format of bind-file. + * + * @see DebugeeBinder + * @see DebugeeArgumentHandler + */ +public class BindServer implements Finalizable { + + /** Version of BindServer implementation. */ + public static final long VERSION = 2; + + /** Timeout in milliseconds used for waiting for inner threads. */ + private static long THREAD_TIMEOUT = DebugeeBinder.THREAD_TIMEOUT; // milliseconds + + private static int PASSED = 0; + private static int FAILED = 2; + private static int JCK_BASE = 95; + + private static int TRACE_LEVEL_PACKETS = 10; + private static int TRACE_LEVEL_THREADS = 20; + private static int TRACE_LEVEL_ACTIONS = 30; + private static int TRACE_LEVEL_SOCKETS = 40; + private static int TRACE_LEVEL_IO = 50; + + private static String pathSeparator = System.getProperty("path.separator"); + private static String fileSeparator = System.getProperty("file.separator"); + + private static char pathSeparatorChar = pathSeparator.charAt(0); + private static char fileSeparatorChar = fileSeparator.charAt(0); + + private static Log log = null; + private static Log.Logger logger = null; + private static ArgumentHandler argHandler = null; + + private static String pathConvertions[][] = null; + + private ListeningThread listeningThread = null; + + private int totalRequests = 0; + private int acceptedRequests = 0; + private int unauthorizedRequests = 0; + private int busyRequests = 0; + + /** + * Start BindServer utility from command line. + * This method invokes run() and redirects output + * to System.err. + * + * @param argv list of command line arguments + */ + public static void main (String argv[]) { + System.exit(run(argv,System.err) + JCK_BASE); + } + + /** + * Start BindServer utility from JCK-compatible + * environment. + * + * @param argv list of command line arguments + * @param out outpur stream for log messages + * + * @return FAILED if error occured + * PASSED oterwise + */ + public static int run(String argv[], PrintStream out) { + return new BindServer().runIt(argv, out); + } + + /** + * Perform execution of BindServer. + * This method handles command line arguments, starts seperate + * thread for listening connection from test on remote host, + * and waits for command "exit" from a user. + * Finally it closes all conections and prints connections + * statiscs. + * + * @param argv list of command line arguments + * @param out outpur stream for log messages + * + * @return FAILED if error occured + * PASSED oterwise + */ + private int runIt(String argv[], PrintStream out) { + try { + argHandler = new ArgumentHandler(argv); + } catch (ArgumentHandler.BadOption e) { + out.println("ERROR: " + e.getMessage()); + return FAILED; + } + + if (argHandler.getArguments().length > 0) { + out.println("ERROR: " + "Too many positional arguments in command line"); + return FAILED; + } + + log = new Log(out, argHandler); + log.enableErrorsSummary(false); + log.enableVerboseOnError(false); + logger = new Log.Logger(log, ""); + + Finalizer bindFinalizer = new Finalizer(this); + bindFinalizer.activate(); + + logger.trace(TRACE_LEVEL_THREADS, "BindServer: starting main thread"); + + logger.display("Listening to port: " + argHandler.getBindPortNumber()); + logger.display("Authorizing host: " + argHandler.getDebuggerHost()); + + pathConvertions = new String[][] { + { "TESTED_JAVA_HOME", argHandler.getDebuggerJavaHome(), argHandler.getDebugeeJavaHome() }, + { "TESTBASE", argHandler.getDebuggerTestbase(), argHandler.getDebugeeTestbase() }, + { "WORKDIR", argHandler.getDebuggerWorkDir(), argHandler.getDebugeeWorkDir() } + }; + + logger.display("Translating pathes:"); + for (int i = 0; i < pathConvertions.length; i++) { + logger.display(pathConvertions[i][0] + ":" +"\n" + + " " + pathConvertions[i][1] + "\n" + + " =>" + "\n" + + " " + pathConvertions[i][2]); + } + + String windir = argHandler.getDebugeeWinDir(); + if (!(windir == null || windir.equals(""))) { + logger.display("Using WINDIR: \n" + + " " + argHandler.getDebugeeWinDir()); + } + + BufferedReader stdIn = new BufferedReader( + new InputStreamReader(System.in)); + + listeningThread = new ListeningThread(this); + listeningThread.bind(); + listeningThread.start(); + + System.out.println("\n" + + "BindServer started" + "\n" + + "Type \"exit\" to shut down BindServer" + + "\n"); + + for (;;) { + try { + String userInput = stdIn.readLine(); + if (userInput == null || userInput.equals("exit") + || userInput.equals("quit")) { + logger.display("Shutting down BindServer"); + stdIn.close(); + stdIn = null; + break; + } else if (userInput.trim().equals("")) { + continue; + } else { + System.out.println("ERROR: Unknown command: " + userInput); + } + } catch(IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while reading console command:\n\t" + + e); + } + } + + printSummary(System.out); + + logger.trace(TRACE_LEVEL_THREADS, "BindServer: exiting main thread"); + try { + finalize(); + } catch (Throwable e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while finalization of BindServer:\n\t" + e); + } + + return PASSED; + } + + /** + * Print usefull summary statistics about connections occured. + * + * @param out output stream for printing statistics + */ + private void printSummary(PrintStream out) { + out.println("\n" + + "Connections summary:" + "\n" + + " Tolal connections: " + totalRequests + "\n" + + " Accepted authorized: " + acceptedRequests + "\n" + + " Rejected unauthorized " + unauthorizedRequests + "\n" + + " Rejected being busy: " + busyRequests + "\n"); + }; + + /** + * Check if given path starts with the specified prefix taking + * into account difference between slashChar used in path + * and fileSeparatorChar used in prefix. + * + * @param path path to check + * @param prefix prefix to compare with + * @param slashChar file separator used in path + */ + private static boolean checkPathPrefix(String path, String prefix, char slashChar) { + int prefixLength = prefix.length(); + if (prefixLength > path.length()) { + return false; + } + for (int i = 0; i < prefixLength; i++) { + char pathChar = path.charAt(i); + char prefixChar = prefix.charAt(i); + + if (pathChar != prefixChar) { + if ((pathChar == slashChar || pathChar == fileSeparatorChar + || pathChar == '\\' || pathChar == '/') + && (prefixChar == slashChar || prefixChar == fileSeparatorChar + || prefixChar == '\\' || prefixChar == '/')) { + // do nothing + } else { + return false; + } + } + } + return true; + } + + /** + * Convert given path according to list of prefixes from + * pathConvertions table. + * + * @param path path for converting + * @param slash file separator used in path + * @param name path identifier used for error messages + * @param strict force throwing Failure if path is not matched + * + * @return string with the converted path + * + * @throws Failure if path does not matched for translation + */ + private static String convertPath(String path, String slash, String name, boolean strict) { + if (path == null) + return null; + + char slashChar = slash.charAt(0); + + for (int i = 0; i < pathConvertions.length; i++) { + String from = pathConvertions[i][1]; + String to = pathConvertions[i][2]; + if (checkPathPrefix(path, from, slashChar)) { + return (to + path.substring(from.length())).replace(slashChar, fileSeparatorChar); + } + } + if (strict) { + throw new Failure("Path not matched for translation " + name + ":\n\t" + path); + } + return path; + } + + /** + * Convert given list of pathes according to list of prefixes from + * pathConvertions table by invoking convertPath() + * for each path from the list. + * + * @param list list of pathes for converting + * @param slash file separator used in pathes + * @param name path identifier used for error messages + * @param strict force throwing Failure if some path is not matched + * + * @return list of strings with converted pathes + * + * @throws Failure if some path does not matched for translation + * + * @see #convertPath() + */ + private static String[] convertPathes(String[] list, String slash, String name, boolean strict) { + String[] converted = new String[list.length]; + for (int i = 0; i < list.length; i++) { + converted[i] = convertPath(list[i], slash, name, strict); + } + return converted; + } + + /** + * Pause current thread for specified amount of time in milliseconds, + * This method uses Object.wait(long) method as a reliable + * method which prevents whole VM from suspending. + * + * @param millisecs - amount of time in milliseconds + */ + private static void sleeping(int millisecs) { + Object obj = new Object(); + + synchronized(obj) { + try { + obj.wait(millisecs); + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + new Failure("Thread interrupted while sleeping:\n\t" + e); + } + } + } + + /** + * Wait for given thread finished for specified timeout or + * interrupt this thread if not finished. + * + * @param thr thread to wait for + * @param millisecs timeout in milliseconds + */ + private static void waitInterruptThread(Thread thr, long millisecs) { + if (thr != null) { + String name = thr.getName(); + try { + if (thr.isAlive()) { + logger.trace(TRACE_LEVEL_THREADS, "Waiting for thread: " + name); + thr.join(millisecs); + } + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure ("Thread interrupted while waiting for another thread:\n\t" + + e); + } finally { + if (thr.isAlive()) { + logger.trace(TRACE_LEVEL_THREADS, "Interrupting not finished thread: " + name); + thr.interrupt(); +/* + logger.display("Stopping not finished thread: " + thr); + thr.stop(); + */ + } + } + } + } + + /** + * Wait for given thread finished for default timeout + * THREAD_TIMEOUT and + * interrupt this thread if not finished. + * + * @param thr thread to wait for + */ + private static void waitInterruptThread(Thread thr) { + waitInterruptThread(thr, THREAD_TIMEOUT); + } + + /** + * Close BindServer by finishing all threads and closing + * all conections. + */ + public synchronized void close() { + if (listeningThread != null) { + listeningThread.close(); + listeningThread = null; + } + } + + /** + * Make finalization of BindServer object by invoking + * method close(). + * + * @see #close() + */ + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + + /** + * Make finalization of BindServer object at program exit + * by invoking method finalize(). + * + * @see #finalize() + */ + public void finalizeAtExit() throws Throwable { + finalize(); + logger.trace(TRACE_LEVEL_THREADS, "BindServer: finalization at exit completed"); + } + +///////// Thread listening a TCP/IP socket ////////// + + /** + * An inner thread used for listening connection from remote test + * and starting separate serving thread for each accepted connection. + * + * @see ServingThread + */ + private static class ListeningThread extends Thread { + private volatile boolean shouldStop = false; + private volatile boolean closed = false; + + private BindServer owner = null; + private volatile ServingThread servingThread = null; + private volatile int taskCount = 0; + + private ObjectOutputStream socOut = null; + private ObjectInputStream socIn = null; + + private String autorizedHostName = argHandler.getDebuggerHost(); + private InetAddress autorizedInetAddresses[] = null; + private int port = argHandler.getBindPortNumber(); + private Socket socket = null; + private ServerSocket serverSocket = null; + private InetAddress clientInetAddr = null; + private String clientHostName = null; + private SocketConnection connection = null; + + /** + * Make listening thread for given BindServer object + * as an owner and bind it to listening port by invoking method + * bind(). + * + * @see bind() + */ + public ListeningThread(BindServer owner) { + super("ListeningThread"); + this.owner = owner; + try { + autorizedInetAddresses = InetAddress.getAllByName(autorizedHostName); + } catch (UnknownHostException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Cannot resolve DEBUGGER_HOST value: " + autorizedHostName); + } + } + + /** + * Bind ServerSocket to the specified port. + */ + public void bind() { + for (int i = 0; !shouldStop && i < DebugeeBinder.CONNECT_TRIES; i++) { + try { + logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: binding to server socket ..."); + // length of the queue = 2 + serverSocket = new ServerSocket(port, 2); + // timeout for the ServerSocket.accept() + serverSocket.setSoTimeout(DebugeeBinder.CONNECT_TRY_DELAY); + logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: socket bound: " + serverSocket); + logger.display("Bound to listening port"); + return; + } catch (BindException e) { + logger.display("Socket binding try #" + i + " failed:\n\t" + e); + sleeping(DebugeeBinder.CONNECT_TRY_DELAY); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while binding to socket:\n\t" + + e); + } + } + throw new Failure("Unable to bind to socket after " + + DebugeeBinder.CONNECT_TRIES + " tries"); + } + + /** + * Accept socket connection from authorized remote host and + * start separate SrvingThread to handle each connection. + * Connection from unauthorized hosts or connections made while + * current connection is alive are rejected. + * + * @see ServingThread + * @see #llowConnection() + * @see allowServing() + */ + public void run() { + String reply = null; + + logger.trace(TRACE_LEVEL_THREADS, "ListeningThread: started"); + logger.display("Listening for connection from remote host"); + while(!(shouldStop || isInterrupted())) { + try { + try { + logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: waiting for connection from test"); + socket = serverSocket.accept(); + logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: connection accepted"); + } catch(InterruptedIOException e) { +// logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: timeout of waiting for connection from test"); + continue; + } + owner.totalRequests++; + logger.display(""); + clientInetAddr = socket.getInetAddress(); + clientHostName = clientInetAddr.getHostName(); + logger.display("Connection #" + owner.totalRequests + + " requested from host: " + clientHostName); + connection = new SocketConnection(logger, "BindServer"); +// connection.setPingTimeout(DebugeeBinder.PING_TIMEOUT); + connection.setSocket(socket); + socket = null; + if (allowConnection()) { + if (allowServing()) { + owner.acceptedRequests++; + reply = "host authorized: " + clientHostName; + logger.display("Accepting connection #" + owner.acceptedRequests + + ": " + reply); + servingThread = new ServingThread(this, connection); + servingThread.start(); + cleanHostConnection(); + } else { + owner.busyRequests++; + reply = "BindServer is busy"; + logger.complain("Rejecting connection #" + owner.busyRequests + + ": " + reply); + connection.writeObject(new RequestFailed(reply)); + closeHostConnection(); + } + } else { + owner.unauthorizedRequests++; + reply = "host unauthorized: " + clientHostName; + logger.complain("Rejecting connection #" + owner.unauthorizedRequests + + ": " + reply); + connection.writeObject(new RequestFailed(reply)); + closeHostConnection(); + } + } catch (Exception e) { + logger.complain("Caught exception while accepting connection:\n" + e); + e.printStackTrace(log.getOutStream()); + } + } + logger.trace(TRACE_LEVEL_THREADS, "ListeningThread: exiting"); + closeConnection(); + } + + /** + * Check if the connection made is from authorized host. + * + * @return true if connection is allowed because host authorized + * false if connection is rejected because host unauthorized + */ + private boolean allowConnection() { + // check if local host from loopback address + if (autorizedHostName.equals("localhost")) + return clientInetAddr.isLoopbackAddress(); + + // check if equal hostname + if (autorizedHostName.equals(clientHostName)) + return true; + + // check if equal host address + for (int i = 0; i < autorizedInetAddresses.length; i++) { + if (clientInetAddr.equals(autorizedInetAddresses[i])) { + return true; + } + } + return false; + } + + /** + * Check if no current connection exists or it is dead. + * If current connection presents it will be tested by pinging + * remote host and aborted if host sends no reply. If an alive + * connection exists, new connection will be rejected. + * + * @return true if no alive connection exists + * false otherwise + */ + private boolean allowServing() { + if (servingThread == null) { + return true; + } + if (servingThread.done) { + return true; + } + if (!servingThread.isConnectionAlive()) { + logger.display("# WARNING: Previous connection from remote host is dead: aborting connection"); + servingThread.close(); + servingThread = null; + return true; + } + +/* + logger.complain("Previous connection from remote host is alive: starting new connection"); + servingThread = null; + return true; + */ + logger.complain("Previous connection from remote host is alive: reject new connection"); + return false; + } + + /** + * Wait for this thread finished + * for specified timeout or interrupt it. + * + * @param millis timeout in milliseconds + */ + public void waitForThread(long millis) { + shouldStop = true; + waitInterruptThread(this, millis); + } + + /** + * Close socket connection from remote host. + */ + private void closeHostConnection() { + if (connection != null) { + connection.close(); + } + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + logger.complain("Caught IOException while closing socket:\n\t" + + e); + } + socket = null; + } + } + + /** + * Assign to connection and socket objects + * but do not close them. + */ + private void cleanHostConnection() { + connection = null; + socket = null; + } + + /** + * Close all connections and sockets. + */ + private void closeConnection() { + closeHostConnection(); + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException e) { + logger.complain("Caught IOException while closing ServerSocket:\n\t" + + e); + } + serverSocket = null; + } + } + + /** + * Close thread by closing all connections and waiting + * foor thread finished. + * + * @see #closeConnection() + */ + public synchronized void close() { + if (closed) { + return; + } + closeHostConnection(); + if (servingThread != null) { + servingThread.close(); + servingThread = null; + } + waitForThread(THREAD_TIMEOUT); + closeConnection(); + closed = true; + logger.trace(TRACE_LEVEL_THREADS, "ListeningThread closed"); + } + + } // ListeningThread + +///////// Thread working with a communication channel ////////// + + /** + * An internal thread for handling each connection from a test + * on remote host. It reads requests from test and starts separate + * LaunchingThread to execute each request. + * + * @see LaunchingThread + */ + private static class ServingThread extends Thread { + private volatile boolean shouldStop = false; + private volatile boolean closed = false; + private volatile boolean done = false; + + private ListeningThread owner = null; + private LaunchingThread launchingThread = null; + + private SocketConnection connection = null; + + /** + * Make serving thread with specified input/output connection streams + * and given Listenerthread as an owner. + * + * @param owner owner of this thread + * @param connection established socket connection with test + */ + public ServingThread(ListeningThread owner, SocketConnection connection) { + super("ServingThread"); + this.owner = owner; + this.connection = connection; + } + + /** + * Read requests from socket connection and start LaunchingThread + * to perform each requested action. + */ + public void run() { + logger.trace(TRACE_LEVEL_THREADS, "ServingThread: starting handling requests from debugger"); + try { + // sending OK(version) + logger.trace(TRACE_LEVEL_ACTIONS, "ServingThread: sending initial OK(VERSION) to debugger"); + connection.writeObject(new OK(VERSION)); + + // receiving TaskID(id) + logger.trace(TRACE_LEVEL_IO, "ServingThread: waiting for TaskID from debugger"); + Object taskID = connection.readObject(); + logger.trace(TRACE_LEVEL_IO, "ServingThread: received TaskID from debugger: " + taskID); + if (taskID instanceof TaskID) { + String id = ((TaskID)taskID).id; + owner.taskCount++; + logger.println("[" + owner.taskCount + "/" + owner.owner.totalRequests + "]: " + id); + } else { + throw new Failure("Unexpected TaskID received form debugger: " + taskID); + } + + // starting launching thread + launchingThread = new LaunchingThread(this, connection); + launchingThread.start(); + + // receiving and handling requests + while(!(shouldStop || isInterrupted())) { + logger.trace(TRACE_LEVEL_IO, "ServingThread: waiting for request from debugger"); + Object request = connection.readObject(); + logger.trace(TRACE_LEVEL_IO, "ServingThread: received request from debugger: " + request); + if (request == null) { + logger.display("Connection closed"); + break; + } else if (request instanceof Disconnect) { + logger.display("Closing connection by request"); + request = null; + break; + } else { + boolean success = false; + long timeToFinish = System.currentTimeMillis() + THREAD_TIMEOUT; + while (System.currentTimeMillis() < timeToFinish) { + if (launchingThread.doneRequest()) { + success = true; + logger.trace(TRACE_LEVEL_ACTIONS, "ServingThread: asking launching thread to handle request: " + request); + launchingThread.handleRequest(request); + break; + } + try { + launchingThread.join(DebugeeBinder.TRY_DELAY); + } catch (InterruptedException e) { + throw new Failure("ServingThread interrupted while waiting for LaunchingThread:\n\t" + + e); + } + } + if (!success) { + logger.complain("Rejecting request because of being busy:\n" + request); + connection.writeObject( + new RequestFailed("Busy with handling previous request")); + } + } + } + } catch (Exception e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while handling request:\n\t" + e); + } finally { + logger.trace(TRACE_LEVEL_THREADS, "ServingThread: exiting"); + closeConnection(); + done = true; + } + } + + /** + * Check if present socket connection is alive. + */ + private boolean isConnectionAlive() { + return (connection != null && connection.isConnected()); + } + + /** + * Wait for this thread finished + * for specified timeout or interrupt it. + * + * @param millis timeout in milliseconds + */ + public void waitForThread(long millis) { + shouldStop = true; + waitInterruptThread(this, millis); + } + + /** + * Close socket connection from remote host. + */ + private void closeConnection() { + if (connection != null) { + connection.close(); + } + if (launchingThread != null) { + launchingThread.handleRequest(null); + } + } + + /** + * Close thread closing socket connection and + * waiting for thread finished. + */ + public synchronized void close() { + if (closed) { + return; + } + closeConnection(); + if (launchingThread != null) { + launchingThread.close(); + launchingThread = null; + } + waitForThread(THREAD_TIMEOUT); + closed = true; + logger.trace(TRACE_LEVEL_THREADS, "ServingThread closed"); + } + + } // ServingThread + +///////// Thread serving a particular Binder's request ////////// + + /** + * An internal thread to execute each request from a test on remote host. + * Requests are coming from ServingThread by invoking handleRequest(Object) + * method. + */ + private static class LaunchingThread extends Thread { + private volatile boolean shouldStop = false; + private volatile boolean closed = false; + public volatile boolean done = false; + + private ServingThread owner = null; +// private ProcessWaitingThread waitingThread = null; + private Process process = null; + + private StreamRedirectingThread stdoutRedirectingThread = null; + private StreamRedirectingThread stderrRedirectingThread = null; + + /** Notification about request occurence. */ + private volatile Object notification = new Object(); + /** Request to execute. */ + private volatile Object request = null; + /** Socket stream to send replies to. */ + private SocketConnection connection = null; + + /** + * Make thread for executing requests from a test and + * send reply. + * + * @param owner owner of this thread + * @connection socket connection for sending replies + */ + public LaunchingThread(ServingThread owner, SocketConnection connection) { + super("LaunchingThread"); + this.owner = owner; + this.connection = connection; + } + + /** + * Notify this thread that new request has come. + * + * @param request request to execute + */ + public void handleRequest(Object request) { + synchronized (notification) { + this.request = request; + notification.notifyAll(); + } + } + + /** + * Check if request has been executed. + */ + public boolean doneRequest() { + return done; + } + + /** + * Wait for request notification from ServingThread + * and execute an action according to the request. + * Request null means thread should finish. + */ + public void run() { + logger.trace(TRACE_LEVEL_THREADS, "LaunchingThread: started to handle request"); + done = true; + while (!isInterrupted()) { + // wait for new request notification + logger.trace(TRACE_LEVEL_ACTIONS, "LaunchingThread: waiting for request"); + synchronized (notification) { + try { + notification.wait(); + } catch (InterruptedException e) { + logger.complain("LaunchingThread interrupted while waiting for request:\n\t" + + e); + break; + } + } + + // execute the request + try { + logger.trace(TRACE_LEVEL_ACTIONS, "LaunchingThread: handling request: " + request); + if (request == null) { + break; + } else if (request instanceof LaunchDebugee) { + launchDebugee((LaunchDebugee)request); + } else if (request instanceof WaitForDebugee) { + waitForDebugee((WaitForDebugee)request); + } else if (request instanceof DebugeeExitCode) { + debugeeExitCode((DebugeeExitCode)request); + } else if (request instanceof KillDebugee) { + killDebugee((KillDebugee)request); + } else { + String reason = "Unknown request: " + request; + logger.complain(reason); + sendReply(new RequestFailed(reason)); + } + } catch (Exception e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while handling request:\n\t" + e); + } + done = true; + } + done = true; + logger.trace(TRACE_LEVEL_THREADS, "LaunchingThread: exiting"); + closeConnection(); + } + + /** + * Send given reply to remote test. + * + * @param reply reply object to send + */ + public void sendReply(Object reply) throws IOException { + connection.writeObject(reply); + } + + /** + * Send given output line to remote test. + * + * @param reply wrapper object for output line to send + */ + public void sendStreamMessage(RedirectedStream wrapper) throws IOException { + logger.trace(TRACE_LEVEL_ACTIONS, "Sending output line wrapper to debugger: " + wrapper); + if (connection.isConnected()) { + sendReply(wrapper); + } else { + logger.complain("NOT redirected: " + wrapper.line); + } + } + + /** + * Launch two StreamRedirectingThread threads to redirect + * stdin/stderr output of debuggee VM process via BindServer + * connection. + * + * @param process debuggee VM process + */ + private void launchStreamRedirectors(Process process) { + stdoutRedirectingThread = + new StdoutRedirectingThread(this, process.getInputStream(), + DebugeeProcess.DEBUGEE_STDOUT_LOG_PREFIX); + stdoutRedirectingThread.start(); + stderrRedirectingThread = + new StderrRedirectingThread(this, process.getErrorStream(), + DebugeeProcess.DEBUGEE_STDERR_LOG_PREFIX); + stderrRedirectingThread.start(); + } + + /** + * Execute request for launching debuggee. + * + * @param request request to execute + */ + private void launchDebugee(LaunchDebugee request) throws IOException { + logger.trace(TRACE_LEVEL_ACTIONS, "LaunchDebugee: handle request: " + request); + + if (process != null) { + logger.complain("Unable to launch debuggee: process already launched"); + sendReply(new RequestFailed("Debuggee process already launched")); + return; + } + + try { + String[] cmd = request.cmd; + cmd[0] = convertPath(cmd[0], request.slash, "TESTED_JAVA_HOME", true); + for (int i = 1; i < cmd.length; i++) { + cmd[i] = convertPath(cmd[i], request.slash, "JAVA_ARGS", false); + } + String workDir = convertPath(request.workDir, request.slash, "WORKDIR", true); + String[] classPathes = convertPathes(request.classPathes, request.slash, "CLASSPATH", true); + String windir = argHandler.getDebugeeWinDir(); + + boolean win = (!(windir == null || windir.equals(""))); + String[] envp = new String[win ? 3 : 1] ; + envp[0] = "CLASSPATH=" + ArgumentParser.joinArguments(classPathes, "", pathSeparator); + if (win) { + envp[1] = "WINDIR=" + windir; + envp[2] = "SystemRoot=" + windir; + } + + logger.display("Setting environment:\n" + + " " + ArgumentHandler.joinArguments(envp, "", "\n ")); + logger.display("Setting work dir:\n" + + " " + workDir); + logger.display("Launching debuggee:\n" + + " " + ArgumentHandler.joinArguments(cmd, "\"")); + + process = Runtime.getRuntime().exec(cmd, envp, new File(workDir)); + logger.display(" debuggee launched successfully"); + + launchStreamRedirectors(process); + } catch (Exception e) { + if (!(e instanceof Failure)) { + e.printStackTrace(log.getOutStream()); + } + logger.complain("Caught exception while launching debuggee:\n\t" + e); + sendReply(new CaughtException(e)); + return; + } + + sendReply(new OK()); + } + + /** + * Execute request for waiting for debuggee exited. + * + * @param request request to execute + */ + private void waitForDebugee(WaitForDebugee request) throws IOException { + logger.trace(TRACE_LEVEL_ACTIONS, "WaitForDebugee: handle request: " + request); + + if (process == null) { + String reply = "No debuggee process to wait for"; + logger.complain(reply); + sendReply(new RequestFailed(reply)); + return; + } + + logger.display("Waiting for debuggee to exit"); +/* + // because timeout is not supported now + // we do not use separate thread for waiting for process + // and so following lines are commented out + + waitingThread = new ProcessWaitingThread(); + logger.trace(TRACE_LEVEL_ACTIONS, "LaunchingThread: starting thread for waiting for debugee process"); + waitingThread.start(); + try { + waitingThread.join(request.timeout); + if (waitingThread.isAlive()) { + String reply = "Timeout exceeded while waiting for debuggee to exit"; + logger.complain(reply); + waitingThread.interrupt(); + sendReply(socOut, new RequestFailed(reply)); + return; + } + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while waiting for debuggee:\n\t" + e); + sendReply(new CaughtException(e)); + return; + } + int exitStatus = waitingThread.exitStatus; + waitingThread = null; + */ + int exitStatus; + try { + exitStatus = process.waitFor(); + waitForRedirectors(THREAD_TIMEOUT); + process.destroy(); + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while waiting for debuggee process to exit:\n\t" + + e); + sendReply(new CaughtException(e)); + return; + } + logger.display(" debuggee exited with exit status: " + exitStatus); + sendReply(new OK(exitStatus)); + } + + /** + * Execute request for returning debuggee exit code. + * + * @param request request to execute + */ + private void debugeeExitCode(DebugeeExitCode request) throws IOException { + logger.trace(TRACE_LEVEL_ACTIONS, "DebugeeExitCode: handle request: " + request); + + if (process == null) { + String reply = "No debuggee process to get exit code for"; + logger.complain(reply); + sendReply(new RequestFailed(reply)); + return; + } + + int exitStatus = 0; + try { + exitStatus = process.exitValue(); + } catch (IllegalThreadStateException e) { + logger.display("# WARNING: Caught exception while getting exit status of debuggee:\n\t" + + e); + sendReply(new CaughtException(e)); + return; + } + logger.trace(TRACE_LEVEL_ACTIONS, "DebugeeExitCode: return debuggee exit status: " + exitStatus); + sendReply(new OK(exitStatus)); + } + + /** + * Execute request for unconditional terminating debuggee process. + * + * @param request request to execute + */ + private void killDebugee(KillDebugee request) throws IOException { + logger.trace(TRACE_LEVEL_ACTIONS, "killDebugee: handle request: " + request); + + if (process == null) { + String reply = "No debuggee process to kill"; + logger.complain(reply); + sendReply(new RequestFailed(reply)); + return; + } + + logger.trace(TRACE_LEVEL_ACTIONS, "killDebugee: killing debuggee process"); + process.destroy(); + + logger.trace(TRACE_LEVEL_ACTIONS, "killDebugee: debuggee process killed"); + sendReply(new OK()); + } + + /** + * Terminate debigee VM process if still alive. + */ + private void terminateDebugeeAtExit() { + if (process != null) { + logger.trace(TRACE_LEVEL_ACTIONS, "Checking that debuggee process has exited correctly"); + try { + int value = process.exitValue(); + } catch (IllegalThreadStateException e) { + logger.complain("Debuggee process has not exited correctly: trying to kill it"); + process.destroy(); + try { + int value = process.exitValue(); + } catch (IllegalThreadStateException ie) { + logger.complain("Debuggee process is alive after killing it"); + } + process = null; + return; + } + logger.trace(TRACE_LEVEL_ACTIONS, "Debuggee process has exited correctly"); + } + } + + /** + * Wait for stream redirecting threads finished + * for specified timeout. + * + * @param millis timeout in milliseconds + */ + private void waitForRedirectors(long millis) { + try { + if (stdoutRedirectingThread != null) { + stdoutRedirectingThread.join(millis); + } + if (stderrRedirectingThread != null) { + stderrRedirectingThread.join(millis); + } + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while waiting for debuggee process exited:\n\t" + + e); + } + } + + /** + * Wait for this thread finished + * for specified timeout or interrupt it. + * + * @param millis timeout in milliseconds + */ + public void waitForThread(long millis) { + shouldStop = true; + handleRequest(null); + waitInterruptThread(this, millis); + } + + /** + * Close connection with debuggee. + */ + public void closeConnection() { + // no connections to close + } + + /** + * Close thread by closing all connections with debuggee, + * finishing all redirectors and wait for thread finished. + */ + public synchronized void close() { + if (closed) { + return; + } + closeConnection(); + terminateDebugeeAtExit(); + if (stdoutRedirectingThread != null) { + stdoutRedirectingThread.close(); + stdoutRedirectingThread = null; + } + if (stderrRedirectingThread != null) { + stderrRedirectingThread.close(); + stderrRedirectingThread = null; + } + waitForThread(THREAD_TIMEOUT); + closed = true; + logger.trace(TRACE_LEVEL_THREADS, "LaunchingThread closed"); + } + + /** + * An inner thread for waiting for debuggee process exited + * and saving its exit status. (currently not used) + */ +/* + private class ProcessWaitingThread extends Thread { + int exitStatus = 0; + + ProcessWaitingThread() { + super("ProcessWaitingThread"); + } + + public void run() { + logger.trace(TRACE_LEVEL_THREADS, "ProcessWaitingThread: starting waiting for process"); + try { + exitStatus = process.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while waiting for debuggee process:\n\t" + + e); + } + logger.trace(TRACE_LEVEL_ACTIONS, "ProcessWaitingThread: process finished with status: " + exitStatus); + logger.trace(TRACE_LEVEL_THREADS, "ProcessWaitingThread: exiting"); + } + + public synchronized void close() { + logger.trace(TRACE_LEVEL_THREADS, "ProcessWaitingThread closed"); + } + + } // ProcessWaitingThread + */ + } // LaunchingThread + +///////// Redirecting threads ///////// + + /** + * An abstract base class for internal threads which redirects stderr/stdout + * output from debuggee process via BindServer connection. + *

      + * Two derived classes will redirect stderr or stdout stream + * by enwrapping stream line by DebugeeStderr or + * DebugeeStderr objects. They should implement only one + * abstract method enwrapLine(String) to make the difference. + */ + public static abstract class StreamRedirectingThread extends Thread { + private volatile boolean shouldStop = false; + private volatile boolean closed = false; + + private LaunchingThread owner = null; + + private BufferedReader bin = null; + private String prefix = null; + + /** + * Make a thread to enwrap and redirect lines from specified + * input stream with given prefix. + * + * @param owner owner of this thread + * @param is input stream to redirect lines from + * @param prefix prefix to add to each line + */ + public StreamRedirectingThread(LaunchingThread owner, InputStream is, String prefix) { + super("StreamRedirectingThread"); + this.prefix = prefix; + this.owner = owner; + bin = new BufferedReader(new InputStreamReader(is)); + } + + /** + * Read lines from an input stream, enwrap them, and send to remote + * test via BindServer connection. + */ + public void run() { + logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread: starting redirect output stream"); + try { + String line; + logger.trace(TRACE_LEVEL_IO, "StreamRedirectingThread: waiting for line from debuggee output"); + while(!shouldStop) { + line = bin.readLine(); + if (line == null) + break; + owner.sendStreamMessage(enwrapLine(prefix + line)); + } + } catch (EOFException e) { + logger.display("Debuggee output stream closed by process"); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + logger.display("# WARNING: Connection to debuggee output stream aborted:\n\t" + e); + } catch (Exception e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while redirecting debuggee output stream:\n\t" + + e); + } + logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread: exiting"); + closeConnection(); + } + + /** + * Envrap output line by the appropriate wrapper. + * @param line line to enwrap + */ + protected abstract RedirectedStream enwrapLine(String line); + + /** + * Wait for this thread finished or interrupt it. + * + * @param millis timeout in milliseconds + */ + public void waitForThread(long millis) { + shouldStop = true; + waitInterruptThread(this, millis); + } + + /** + * Close redirected process output stream. + */ + public void closeConnection() { + if (closed) { + return; + } + if (bin != null) { + try { + bin.close(); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while closing debuggee output stream:\n\t" + + e); + } + bin = null; + } + closed = true; + logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread closed"); + } + + /** + * Close thread by waiting redirected stream closed + * and finish the thread. + */ + public synchronized void close() { + if (closed) { + return; + } + waitForThread(THREAD_TIMEOUT); + closeConnection(); + closed = true; + logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread closed"); + } + + } // StreamRedirectingThread + + /** + * Particalar case of StreamRedirectingThread to redirect + * stderr stream by enwrapping lines into DebugeeStderr + * objects. + */ + private static class StderrRedirectingThread extends StreamRedirectingThread { + + /** + * Make a thread to redirect stderr output stream. + */ + StderrRedirectingThread(LaunchingThread owner, InputStream is, String prefix) { + super(owner, is, prefix); + setName("StderrRedirectingThread"); + } + + /** + * Enwrap given line into DebugeeStderr object. + */ + protected RedirectedStream enwrapLine(String line) { + return new DebugeeStderr(line); + } + + } + + /** + * Particalar case of StreamRedirectingThread to redirect + * stdout stream by enwrapping lines into DebugeeStdout + * objects. + */ + private static class StdoutRedirectingThread extends StreamRedirectingThread { + + /** + * Make a thread to redirect stdout output stream. + */ + StdoutRedirectingThread(LaunchingThread owner, InputStream is, String prefix) { + super(owner, is, prefix); + setName("StdoutRedirectingThread"); + } + + /** + * Enwrap given line into DebugeeStdout object. + */ + protected RedirectedStream enwrapLine(String line) { + return new DebugeeStdout(line); + } + + } + +///////// BinderServer's packets ////////// + + /** + * Base serializable object to transmit request or reply + * via BindServer connection. + */ + public static class Packet implements Serializable {} + + ///////// Binder's requests ////////// + + /** + * Base class to represent request to BindServer. + */ + public static abstract class Request extends Packet {} + + /** + * This class implements task identification command. + */ + public static class TaskID extends Request { + public String id; + + public TaskID(String id) { + this.id = id; + } + + public String toString() { + return "TaskID: id=" + id; + } + } + + /** + * This class implements a request for launching a debugee. + */ + public static class LaunchDebugee extends Request { + public String slash; // slash symbol used on debugger host + public String[] cmd; // command line arguments as seen on debugger host + public String workDir; // path to working directory as seen on debugger host + public String[] classPathes; // list of class pathes as seen on debugger host + + public LaunchDebugee(String[] cmd, String slash, String workDir, + String[] pathes, String[] classPathes, + String[] libPathes) { + this.cmd = cmd; + this.slash = slash; + this.workDir = workDir; + this.classPathes = classPathes; + } + + public String toString() { + return "LaunchDebugee:" + + "\n\tcommand=" + ArgumentParser.joinArguments(cmd, "\"") + + "\n\tWORKDIR=" + workDir + + "\n\tCLASSPATH=" + ArgumentParser.joinArguments(classPathes, "", ":") + + "\n\tslash=" + slash; + } + } + + /** + * This class implements a request for waiting for debugee + * termination. + */ + public static class WaitForDebugee extends Request { + public long timeout = 0; // timeout in minutes for waiting + + public WaitForDebugee(long value) { + timeout = value; + } + + public String toString() { + return "WaitForDebugee: timeout=" + timeout; + } + } + + /** + * This class implements a request for exit code of + * debugee process. + */ + public static class DebugeeExitCode extends Request { + public String toString() { + return "SebugeeExitCode"; + } + } + + /** + * This class implements a request for killing debugee process. + */ + public static class KillDebugee extends Request { + public String toString() { + return "KillDebugee"; + } + } + + /** + * This class implements a request to disconnect connection with test. + */ + public static class Disconnect extends Request { + public String toString() { + return "Disconnect"; + } + } + + ///////// BindServer's responses ////////// + + /** + * Base class to represent response from BindServer. + */ + public static abstract class Response extends Packet {} + + /** + * This class implements a response that a previoulsy received + * request has been successfully performed. + */ + public static class OK extends Response { + public long info = BindServer.VERSION; // optional additional info + + public OK() { + } + + public OK(long value) { + info = value; + } + + public String toString() { + return "OK(" + info + ")"; + } + } + + /** + * This class implements a response that the BindServer is + * unable to serve a previoulsy received request. + */ + public static class RequestFailed extends Response { + public String reason; // the short explanation of failure + + public RequestFailed(String reason) { + this.reason = reason; + } + + public String toString() { + return "RequestFailed(" + reason + ")"; + } + } + + /** + * This class implements a response that the BindServer is + * unable to serve a previoulsy received request because of + * caught exception. + */ + public static class CaughtException extends RequestFailed { + public CaughtException(Exception cause) { + super("Caught exception: " + cause); + } + } + + ///////// Wrappers for redirected messages ////////// + + /** + * Base class to represent wrappers for redirected streams. + */ + public static class RedirectedStream extends Packet { + public String line; // line containing line from redirected stream + + public RedirectedStream(String str) { + line = str; + } + + public String toString() { + return "RedirectedStream(" + line + ")"; + } + } + + /** + * This class enwraps redirected line of stdout stream. + */ + public static class DebugeeStdout extends RedirectedStream { + + public DebugeeStdout(String str) { + super(str); + } + + public String toString() { + return "DebugeeStdout(" + line + ")"; + } + } + + /** + * This class enwraps redirected line of stderr stream. + */ + public static class DebugeeStderr extends RedirectedStream { + public DebugeeStderr(String str) { + super(str); + } + + public String toString() { + return "DebugeeStderr(" + line + ")"; + } + } + +/////// ArgumentHandler for BindServer command line ///////// + + /** + * This class is used to parse arguments from command line + * and specified bind-file, + */ + private static class ArgumentHandler extends ArgumentParser { + + protected Properties fileOptions; + + /** + * Make parser object for command line arguments. + * + * @param args list of command line arguments + */ + public ArgumentHandler(String[] args) { + super(args); + } + + /** + * Check if given command line option is aloowed. + * + * @param option option name + * @param value option value + */ + protected boolean checkOption(String option, String value) { + if (option.equals("bind.file")) { + // accept any file name + return true; + } + return super.checkOption(option, value); + } + + /** + * Check if all recignized options are compatible. + */ + protected void checkOptions() { + if (getBindFileName() == null) { + throw new BadOption("Option -bind.file is requred "); + } + super.checkOptions(); + } + + /** + * Check if value of this option points to a existing directory. + * + * @param option option name + * @param dir option value + */ + private void checkDir(String option, String dir) { + File file = new File(dir); + if (!file.exists()) { + throw new BadOption(option + " does not exist: " + dir); + } + if (!file.isAbsolute()) { + throw new BadOption(option + " is not absolute pathname: " + dir); + } + if (!file.isDirectory()) { + throw new BadOption(option + " is not directory: " + dir); + } + } + + /** + * Check if option from bind-file is allowed. + * + * @param option option name + * @param value option value + */ + protected boolean checkAdditionalOption(String option, String value) { + + if (option.equals("DEBUGGER_HOST")) { + // accept any hostname + return true; + } + + if (option.equals("BINDSERVER_PORT")) { + // accept only integer value + try { + int port = Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new Failure("Not integer value of bind-file option " + option + + ": " + value); + } + return true; + } + + if (option.equals("DEBUGGER_TESTED_JAVA_HOME") + || option.equals("DEBUGGER_WORKDIR") + || option.equals("DEBUGGER_TESTBASE")) { + if (value == null || value.equals("")) { + throw new BadOption("Empty value of bind-file option " + option); + } + return true; + } + + if (option.equals("DEBUGGEE_TESTED_JAVA_HOME") + || option.equals("DEBUGGEE_WORKDIR") + || option.equals("DEBUGGEE_TESTBASE")) { + if (value == null || value.equals("")) { + throw new BadOption("Empty value of bind-file option " + option); + } + checkDir(option, value); + return true; + } + + if (option.equals("DEBUGGEE_WINDIR")) { + if (!(value == null || value.equals(""))) { + checkDir(option, value); + } + return true; + } + + return false; + } + + /** + * Check if all recignized options form bind-file are compatible. + */ + protected void checkAdditionalOptions() { + + if (getDebuggerJavaHome() == null) { + throw new BadOption("Option DEBUGGER_JAVA_HOME missed from bind-file"); + } + if (getDebuggerWorkDir() == null) { + throw new BadOption("Option DEBUGGER_WORKDIR missed from bind-file"); + } + if (getDebuggerTestbase() == null) { + throw new BadOption("Option DEBUGGER_TESTBASE missed from bind-file"); + } + + if (getDebugeeJavaHome() == null) { + throw new BadOption("Option DEBUGGEE_JAVA_HOME missed from bind-file"); + } + if (getDebugeeWorkDir() == null) { + throw new BadOption("Option DEBUGGEE_WORKDIR missed from bind-file"); + } + if (getDebugeeTestbase() == null) { + throw new BadOption("Option DEBUGGEE_TESTBASE missed from bind-file"); + } + } + + /** + * Parse options form specified bind-file. + */ + protected void parseAdditionalOptions() { + Enumeration keys = fileOptions.keys(); + while (keys.hasMoreElements()) { + String option = (String)keys.nextElement(); + String value = fileOptions.getProperty(option); + if (! checkAdditionalOption(option, value)) { + throw new BadOption("Unrecognized bind-file option: " + option); + } + } + checkAdditionalOptions(); + } + + /** + * Parse all options from command line and specified bind-file. + */ + protected void parseArguments() { + super.parseArguments(); + String fileName = getBindFileName(); + try { + FileInputStream bindFile = new FileInputStream(fileName); + fileOptions = new Properties(); + fileOptions.load(bindFile); + bindFile.close(); + } catch(FileNotFoundException e) { + throw new BadOption("Unable to open bind-file " + fileName + ": " + e); + } catch(IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while reading bind-file:\n" + e); + } + parseAdditionalOptions(); + } + + /** Return name of specified bind-file. */ + public String getBindFileName() { + return options.getProperty("bind.file"); + } + + /** Return specified debuggee host name . */ + public String getDebuggerHost() { + return fileOptions.getProperty("DEBUGGER_HOST", "localhost"); + } + + /** Return string representation of port number for BindServer connection. */ + public String getBindPort() { + return fileOptions.getProperty("BINDSERVER_PORT", "9000"); + } + + /** Return specified port number for BindServer connection. */ + public int getBindPortNumber() { + try { + return Integer.parseInt(getBindPort()); + } catch (NumberFormatException e) { + throw new Failure("Not integer value of BindServer port"); + } + } + + /** Return specified path to tested JDK used for debuggee VM. */ + public String getDebugeeJavaHome() { + return fileOptions.getProperty("DEBUGGEE_TESTED_JAVA_HOME"); + } + + /** Return specified path to tested JDK used for debugger. */ + public String getDebuggerJavaHome() { + return fileOptions.getProperty("DEBUGGER_TESTED_JAVA_HOME"); + } + + /** Return specified path to working dir from debuggee host. */ + public String getDebugeeWorkDir() { + return fileOptions.getProperty("DEBUGGEE_WORKDIR"); + } + + /** Return specified path to working dir from debugger host. */ + public String getDebuggerWorkDir() { + return fileOptions.getProperty("DEBUGGER_WORKDIR"); + } + + /** Return specified path to testbase dir from debuggee host. */ + public String getDebugeeTestbase() { + return fileOptions.getProperty("DEBUGGEE_TESTBASE"); + } + + /** Return specified path to testbase dir from debugger host. */ + public String getDebuggerTestbase() { + return fileOptions.getProperty("DEBUGGER_TESTBASE"); + } + + /** Return specified path to system directory on Wimdows platform. */ + public String getDebugeeWinDir() { + return fileOptions.getProperty("DEBUGGEE_WINDIR"); + } + + } // ArgumentHandler + +} // BindServer diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ConversionUtils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ConversionUtils.java new file mode 100644 index 00000000000..c4c33c34fbb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ConversionUtils.java @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jpda; + +/* +Static methods checking whether given primitive type value can be +converted to another primitive type without information loss + +Note: +the spec defines following 2 types of primitive values conversions: + +Widening primitive conversions (don't loose information, but may lose precision): + * byte to short, int, long, float, or double + * short to int, long, float, or double + * char to int, long, float, or double + * int to long, float, or double + * long to float or double + * float to double + +Narrowing primitive conversions (may loose information and may loose precision): + * byte to char + * short to byte or char + * char to byte or short + * int to byte, short, or char + * long to byte, short, char, or int + * float to byte, short, char, int, or long + * double to byte, short, char, int, long, or float + +Examples: + Conversions (int)1234567890 -> (float)1.23456794E9 and (float)1.5 -> (int)1 loose precision. + Conversion (byte)-1 -> (char) ffff and (double)Double.MAX_VALUE -> (int)Integer.MAX_VALUE loose information. + +(See the "JavaTM Language Specification" section 5.2 for more information +on assignment compatibility) + */ +public class ConversionUtils { + + /* + * Methods checking that value can be converted to the value of the + * same type (like 'informationLossByteToByte') were added to simplify + * clients coding (when this methods exist clients shouldn't handle this case + * in a specific way) + */ + + /* + * Byte + */ + public static boolean informationLossByteToByte(Byte value) { + return false; + } + + public static boolean informationLossByteToShort(Byte value) { + return false; + } + + public static boolean informationLossByteToChar(Byte value) { + return (value.byteValue() > Character.MAX_VALUE) || (value.byteValue() < Character.MIN_VALUE); + } + + public static boolean informationLossByteToInt(Byte value) { + return false; + } + + public static boolean informationLossByteToLong(Byte value) { + return false; + } + + public static boolean informationLossByteToFloat(Byte value) { + return false; + } + + public static boolean informationLossByteToDouble(Byte value) { + return false; + } + + /* + * Short + */ + public static boolean informationLossShortToShort(Short value) { + return false; + } + + public static boolean informationLossShortToByte(Short value) { + return (value.shortValue() > Byte.MAX_VALUE) || (value.shortValue() < Byte.MIN_VALUE); + } + + public static boolean informationLossShortToChar(Short value) { + return (value.shortValue() > Character.MAX_VALUE) || (value.shortValue() < Character.MIN_VALUE); + } + + public static boolean informationLossShortToInt(Short value) { + return false; + } + + public static boolean informationLossShortToLong(Short value) { + return false; + } + + public static boolean informationLossShortToFloat(Short value) { + return false; + } + + public static boolean informationLossShortToDouble(Short value) { + return false; + } + + /* + * Char + */ + public static boolean informationLossCharToChar(Character value) { + return false; + } + + public static boolean informationLossCharToByte(Character value) { + return (value.charValue() > Byte.MAX_VALUE) || (value.charValue() < Byte.MIN_VALUE); + } + + public static boolean informationLossCharToShort(Character value) { + return (value.charValue() > Short.MAX_VALUE) || (value.charValue() < Short.MIN_VALUE); + } + + public static boolean informationLossCharToInt(Character value) { + return false; + } + + public static boolean informationLossCharToLong(Character value) { + return false; + } + + public static boolean informationLossCharToFloat(Character value) { + return false; + } + + public static boolean informationLossCharToDouble(Character value) { + return false; + } + + /* + * Integer + */ + public static boolean informationLossIntToInt(Integer value) { + return false; + } + + public static boolean informationLossIntToByte(Integer value) { + return (value.intValue() > Byte.MAX_VALUE) || (value.intValue() < Byte.MIN_VALUE); + } + + public static boolean informationLossIntToShort(Integer value) { + return (value.intValue() > Short.MAX_VALUE) || (value.intValue() < Short.MIN_VALUE); + } + + public static boolean informationLossIntToChar(Integer value) { + return (value.intValue() > Character.MAX_VALUE) || (value.intValue() < Character.MIN_VALUE); + } + + public static boolean informationLossIntToLong(Integer value) { + return false; + } + + public static boolean informationLossIntToFloat(Integer value) { + return false; + } + + public static boolean informationLossIntToDouble(Integer value) { + return false; + } + + /* + * Long + */ + public static boolean informationLossLongToLong(Long value) { + return false; + } + + public static boolean informationLossLongToByte(Long value) { + return (value.longValue() > Byte.MAX_VALUE) || (value.longValue() < Byte.MIN_VALUE); + } + + public static boolean informationLossLongToShort(Long value) { + return (value.longValue() > Short.MAX_VALUE) || (value.longValue() < Short.MIN_VALUE); + } + + public static boolean informationLossLongToChar(Long value) { + return (value.longValue() > Character.MAX_VALUE) || (value.longValue() < Character.MIN_VALUE); + } + + public static boolean informationLossLongToInt(Long value) { + return (value.longValue() > Integer.MAX_VALUE) || (value.longValue() < Integer.MIN_VALUE); + } + + public static boolean informationLossLongToFloat(Long value) { + return false; + } + + public static boolean informationLossLongToDouble(Long value) { + return false; + } + + /* + * Float + */ + public static boolean informationLossFloatToFloat(Float value) { + return false; + } + + public static boolean informationLossFloatToByte(Float value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.floatValue() > Byte.MAX_VALUE) || (value.floatValue() < Byte.MIN_VALUE); + } + + public static boolean informationLossFloatToShort(Float value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.floatValue() > Short.MAX_VALUE) || (value.floatValue() < Short.MIN_VALUE); + } + + public static boolean informationLossFloatToChar(Float value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.floatValue() > Character.MAX_VALUE) || (value.floatValue() < Character.MIN_VALUE); + } + + public static boolean informationLossFloatToInt(Float value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.floatValue() > Integer.MAX_VALUE) || (value.floatValue() < Integer.MIN_VALUE) + || ((int)value.floatValue() != value.floatValue()); + } + + public static boolean informationLossFloatToLong(Float value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.floatValue() > Long.MAX_VALUE) || (value.floatValue() < Long.MIN_VALUE) + || ((long)value.floatValue() != value.floatValue()); + } + + public static boolean informationLossFloatToDouble(Float value) { + return false; + } + + + /* + * Double + */ + public static boolean informationLossDoubleToDouble(Double value) { + return false; + } + + public static boolean informationLossDoubleToByte(Double value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.doubleValue() > Byte.MAX_VALUE) || (value.doubleValue() < Byte.MIN_VALUE); + } + + public static boolean informationLossDoubleToShort(Double value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.doubleValue() > Short.MAX_VALUE) || (value.doubleValue() < Short.MIN_VALUE); + } + + public static boolean informationLossDoubleToChar(Double value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.doubleValue() > Character.MAX_VALUE) || (value.doubleValue() < Character.MIN_VALUE); + } + + public static boolean informationLossDoubleToInt(Double value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.doubleValue() > Integer.MAX_VALUE) || (value.doubleValue() < Integer.MIN_VALUE); + } + + public static boolean informationLossDoubleToLong(Double value) { + if (value.isInfinite()) + return true; + + if (value.isNaN()) + return true; + + return (value.doubleValue() > Long.MAX_VALUE) || (value.doubleValue() < Long.MIN_VALUE) + || ((long)value.doubleValue() != value.doubleValue()); + } + + public static boolean informationLossDoubleToFloat(Double value) { + if (value.isInfinite()) + return false; + + if (value.isNaN()) + return false; + + float f = (float) value.doubleValue(); + + return f != value.doubleValue(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeArgumentHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeArgumentHandler.java new file mode 100644 index 00000000000..bb5abbb80f5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeArgumentHandler.java @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jpda; + +import nsk.share.*; + +import java.io.*; +import java.net.ServerSocket; + +/** + * Parser for JPDA test's launching and connection arguments. + *

      + * DebugeeArgumentHandler handles specific JDI/JDWP/JDB tests + * command line arguments related to launching and connection parameters + * for debugee VM in addition to general arguments recognized by + * ArgumentParser. + *

      + * Following is the list of specific options for + * DebugeeAgrumentHandler: + *

        + *
      • -test.host=<host> - + * address of a host where test executes + *
      • -debugee.host=<host> - + * address of a host where debugee VM executes + *
      • -connector=[attaching|listening] - + * connector type to connect to debugee VM + *
      • -transport=[socket|shmem] - + * transport type to connect to debugee VM + *
      • -transport.port=<port> - + * port number for socket transport + *
      • -transport.shname=<name> - + * shared memory name for shmem transport + *
      • -transport.address=<dynamic> - + * use dynamically allocated unique transport address for JDWP connection + * ignoring settings for -transport.port and -transport.shname + * (this works only with -connector=listening and -transport=socket) + *
      • -debugee.suspend=[yes|no|default] - + * should debugee start in suspend mode or not + *
      • -debugee.launch=[local|remote|manual] - + * launch and bind to debugee VM locally, remotely (via BindSever) or manually + *
      • -debugee.vmhome=<path> - + * path to JDK used for launching debugee VM + *
      • -debugee.vmkind=<name> - + * name of debugee VM launcher executable + *
      • -debugee.vmkeys=<string> - + * additional options for launching debugee VM + *
      • -jvmdi.strict=[yes|no|default] - + * using JVMDI strict mode + *
      • -pipe.port=<port> - + * port number for internal IOPipe connection + *
      • -bind.port=<port> - + * port number for BindServer connection + *
      + *

      + * See also list of basic options recognized by + * ArgumentParser. + *

      + * See also comments to ArgumentParser for list of general + * recognized options and how to work with command line arguments and options. + * + * @see ArgumentParser + * @see nsk.share.jdi.ArgumentHandler + * @see nsk.share.jdwp.ArgumentHandler + */ +public class DebugeeArgumentHandler extends ArgumentParser { + + public static final String DEFAULT_PIPE_PORT = "7123"; + public static final String DEFAULT_TRANSPORT_PORT = "8123"; + public static final String DEFAULT_BIND_PORT = "9123"; + + + /** + * Keep a copy of raw command-line arguments and parse them; + * but throw an exception on parsing error. + * + * @param args Array of the raw command-line arguments. + * + * @throws BadOption If unknown option or illegal + * option value found + * + * @see #setRawArguments(String[]) + */ + public DebugeeArgumentHandler(String args[]) { + super(args); + } + + /** + * Return name of the host where test executes, specified by + * -test.host command line option or + * "localhost" string by default. + * + * @see #setRawArguments(String[]) + */ + public String getTestHost() { + return options.getProperty("test.host", "localhost"); + } + + /** + * Return name of host where the debugee VM is executed, specified by + * -debugee.host command line option or value of + * getTestHost() by default. + * + * @see #getTestHost() + * @see #setRawArguments(String[]) + */ + public String getDebugeeHost() { + return options.getProperty("debugee.host", getTestHost()); + } + + private boolean transportPortInited = false; + /** + * Return string representation of port number for socket transport, + * specified by -tranport.port command line option or + * "DEFAULT_TRANSPORT_PORT" string by default. + * + * @see #getTransportPortIfNotDynamic() + * @see #getTransportPortNumber() + * @see #setTransportPortNumber(int) + * @see #setRawArguments(String[]) + */ + synchronized public String getTransportPort() { + String port = options.getProperty("transport.port"); + if (port == null) { + if (!transportPortInited) { + port = findFreePort(); + if (port == null) { + port = DEFAULT_TRANSPORT_PORT; + } + options.setProperty("transport.port", port); + transportPortInited = true; + } + } + return port; + } + + /** + * Return string representation of port number for socket transport, + * specified by -tranport.port command line option or + * "DEFAULT_TRANSPORT_PORT" string by default in case transport address is + * not dynamic. + * Otherwise null is returned. + * + * @see #getTransportPort() + * @see #getTransportPortNumber() + * @see #setTransportPortNumber(int) + * @see #setRawArguments(String[]) + */ + public String getTransportPortIfNotDynamic() { + return ( isTransportAddressDynamic() ? + null : getTransportPort() ); + } + + /** + * Return string port number for socket transport, + * specified by -debugee.port command line option or + * DEFAULT_TRANSPORT_PORT port number by default. + * + * @see #getTransportPort() + * @see #getTransportPortIfNotDynamic() + * @see #setTransportPortNumber(int) + * @see #setRawArguments(String[]) + */ + public int getTransportPortNumber() { + String value = getTransportPort(); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not integer value of \"-transport.port\" argument: " + value); + } + } + + /** + * Add or replace value of option -transport.port in options list + * with the specified port number. + * + * @see #getTransportPortNumber() + * @see #setRawArguments(String[]) + */ + public void setTransportPortNumber(int port) { + String value = Integer.toString(port); + setOption("-", "transport.port", value); + } + + /** + * Return shared name for shmem transport, specified by + * -transport.shname command line option, or + * "nskjpdatestchannel" + a process unique string by default. + * + * @see #setTransportSharedName(String) + * @see #setRawArguments(String[]) + */ + // Use a unique id for this process by default. This makes sure that + // tests running concurrently do not use the same shared name. + private static String defaultTransportSharedName + = "nskjpdatestchannel" + ProcessHandle.current().pid(); + public String getTransportSharedName() { + return options.getProperty("transport.shname", defaultTransportSharedName); + } + + /** + * Add or replace value of option -transport.shname in options list + * with the specified name. + * + * @see #getTransportSharedName() + * @see #setRawArguments(String[]) + */ + public void setTransportSharedName(String name) { + setOption("-", "transport.shname", name); + } + + /** + * Return true if -transport.address=dynamic command line option + * is specified. + * + * @see #setRawArguments(String[]) + */ + public boolean isTransportAddressDynamic() { + String value = options.getProperty("transport.address", null); + if (value != null && value.equals("dynamic")) + return true; + return false; + } + + /** + * Return suspend mode for launching debugee VM, specified by + * -debugee.suspend command line option, or + * "default" string by default. + * + * @see #isDefaultDebugeeSuspendMode() + * @see #willDebugeeSuspended() + * @see #setRawArguments(String[]) + */ + public String getDebugeeSuspendMode() { + return options.getProperty("debugee.suspend", "default"); + } + + /** + * Return true if default suspend mode is used + * for launching debugee VM. + * + * @see #getDebugeeSuspendMode() + * @see #willDebugeeSuspended() + */ + public boolean isDefaultDebugeeSuspendMode() { + String mode = getDebugeeSuspendMode(); + return mode.equals("default"); + } + + /** + * Return true if debugee VM will be suspended after launching, + * either according to specified suspend mode or by default. + * + * @see #getDebugeeSuspendMode() + * @see #isDefaultDebugeeSuspendMode() + */ + public boolean willDebugeeSuspended() { + if (isLaunchedLocally()) { + String mode = getDebugeeSuspendMode(); + return mode.equals("no"); + } + return true; + } + + private boolean pipePortInited = false; + /** + * Return string representation of the port number for IOPipe connection, + * specified by -pipe.port command line option, or + * "DEFAULT_PIPE_PORT" string by default. + * + * @see #getPipePortNumber() + * @see #setPipePortNumber(int) + * @see #setRawArguments(String[]) + */ + synchronized public String getPipePort() { + String port = options.getProperty("pipe.port"); + if (port == null) { + if (!pipePortInited) { + port = findFreePort(); + if (port == null) { + port = DEFAULT_PIPE_PORT; + } + pipePortInited = true; + options.setProperty("pipe.port", port); + } + } + return port; + } + + /** + * Return port number for IOPipe connection, + * specified by -pipe.port command line option, or + * DEFAULT_PIPE_PORT port number by default. + * + * @see #getPipePort() + * @see #setPipePortNumber(int) + * @see #setRawArguments(String[]) + */ + public int getPipePortNumber() { + String value = getPipePort(); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not integer value of \"-pipe.port\" argument: " + value); + } + } + + /** + * Add or replace value of option -pipe.port in options list + * with the specified port number. + * + * @see #getPipePortNumber() + * @see #setRawArguments(String[]) + */ + public void setPipePortNumber(int port) { + String value = Integer.toString(port); + setOption("-", "pipe.port", value); + } + + /** + * Return debugee VM launching mode, specified by + * -launch.mode command line option, or + * "local" string by default. + * + * Possible values for this option are: + *

        + *
      • "local" + *
      • "remote" + *
      • "manual" + *
      + * + * @see #isLaunchedLocally() + * @see #isLaunchedRemotely() + * @see #isLaunchedManually() + * @see #setRawArguments(String[]) + */ + public String getLaunchMode() { + return options.getProperty("debugee.launch", "local"); + } + + /** + * Return true if debugee should be launched locally. + * + * @see #getLaunchMode() + */ + public boolean isLaunchedLocally() { + return getLaunchMode().equals("local"); + } + + /** + * Return true if debugee should be launched remotely via + * BindServer. + * + * @see #getLaunchMode() + */ + public boolean isLaunchedRemotely() { + return getLaunchMode().equals("remote"); + } + + /** + * Return true if debugee should be launched manually by user. + * + * @see #getLaunchMode() + */ + public boolean isLaunchedManually() { + return getLaunchMode().equals("manual"); + } + + /** + * Return additional options for launching debugee VM, specified by + * -launch.options command line option, or + * empty string by default. + * + * @see #setRawArguments(String[]) + */ + public String getLaunchOptions() { + String result = options.getProperty("debugee.vmkeys", "").trim(); + if (result.startsWith("\"") && result.endsWith("\"")) { + result = result.substring(1, result.length() - 1); + } + return result; + } + + /** + * Return name of debugee VM launcher executable, specified by + * -launch.vmexec command line option, or + * "java" string by default. + * + * @see #setRawArguments(String[]) + */ + public String getLaunchExecName() { + return options.getProperty("debugee.vmkind", "java"); + } + + /** + * Return full path to debugee VM launcher executable. + * + * @see #getLaunchExecName() + * @see #getLaunchExecPath(String) + * @see #getDebugeeJavaHome() + */ + public String getLaunchExecPath() { + String java_home = getDebugeeJavaHome(); + return getLaunchExecPath(java_home); + } + + /** + * Return full path to VM launcher executable using givet JAVA_HOME path. + * + * @see #getLaunchExecName() + */ + public String getLaunchExecPath(String java_home) { + String filesep = System.getProperty("file.separator"); + return java_home + filesep + "bin" + filesep + getLaunchExecName(); + } + + /** + * Return full JAVA_HOME path for debugee VM. + * + * @see #getLaunchExecName() + */ + public String getDebugeeJavaHome() { + String java_home = System.getProperty("java.home"); + return options.getProperty("debugee.vmhome", java_home); + } + + /** + * Return true if default debuggee VM launcher executable is used. + * + * @see #getLaunchExecName() + */ + public boolean isDefaultLaunchExecName() { + String vmkind = options.getProperty("debugee.vmkind", null); + return (vmkind == null); + } + + /** + * Return true if default JAVA_HOME path for debuggee VM is used. + * + * @see #getDebugeeJavaHome() + */ + public boolean isDefaultDebugeeJavaHome() { + String java_home = options.getProperty("debugee.vmhome", null); + return (java_home == null); + } + + private boolean bindPortInited = false; + /** + * Return string representation of the port number for BindServer connection, + * specified by -bind.port command line option, or + * "DEFAULT_BIND_PORT" string by default. + * + * @see #getBindPortNumber() + * @see #setRawArguments(String[]) + */ + public String getBindPort() { + String port = options.getProperty("bind.port"); + if (port == null) { + if (!bindPortInited) { + port = findFreePort(); + if (port == null) { + port = DEFAULT_BIND_PORT; + } + options.setProperty("bind.port", port); + bindPortInited = true; + } + } + return port; + } + + /** + * Return port number for BindServer connection, + * specified by -bind.port command line option, or + * "DEFAULT_BIND_PORT" port number by default. + * + * @see #getBindPort() + * @see #setRawArguments(String[]) + */ + public int getBindPortNumber() { + String value = getBindPort(); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new TestBug("Not integer value of \"bind.port\" argument: " + value); + } + } + + /** + * Return JVMDI strict mode for launching debugee VM, specified by. + * -jvmdi.strict command line option, or + * "default" string by default. + * + * Possible values for this option are: + *
        + *
      • "yes" + *
      • "no" + *
      • "default" + *
      + * + * @see #setRawArguments(String[]) + */ + public String getJVMDIStrictMode() { + return options.getProperty("jvmdi.strict", "default"); + } + + /** + * Return true if JVMDI strict mode for launching debugeeVM is used^ + * either by specifying in command line or by default. + * + * @see #getJVMDIStrictMode() + * @see #isDefaultJVMDIStrictMode() + * @see #setRawArguments(String[]) + */ + public boolean isJVMDIStrictMode() { + String mode = getJVMDIStrictMode(); + return mode.equals("yes"); + } + + /** + * Return true if JVMDI default strict mode for launching debugee VM is used. + * + * @see #getJVMDIStrictMode() + * @see #isJVMDIStrictMode() + * @see #setRawArguments(String[]) + */ + public boolean isDefaultJVMDIStrictMode() { + String mode = getJVMDIStrictMode(); + return mode.equals("default"); + } + + /** + * Return type of JDI connector used for connecting to debugee VM, specified by + * -connector command line option, or + * "listening" string by default. + * + * Possible values for this option are: + *
        + *
      • "attaching" + *
      • "listening" + *
      + * + * @see #isAttachingConnector() + * @see #isListeningConnector() + * @see #setRawArguments(String[]) + */ + public String getConnectorType() { + return options.getProperty("connector", "listening"); + } + + /** + * Return true if type of the used JDI connector is attaching. + * + * @see #getConnectorType() + */ + public boolean isAttachingConnector() { + return getConnectorType().equals("attaching"); + } + + /** + * Return true if type of the used JDI connector is listening. + * + * @see #getConnectorType() + */ + public boolean isListeningConnector() { + return getConnectorType().equals("listening"); + } + + /** + * Return true if connector type is not actually specified. + * In this case getConnectorType() returns some default connector type. + * + * @see #getConnectorType() + */ + public boolean isDefaultConnector() { + return options.getProperty("connector") == null; + } + + /** + * Return type of JDWP transport for connecting to debugee VM, specified by + * -transport command line option, or + * "socket" string by default. + * + * Possible values for this option are: + *
        + *
      • "socket" + *
      • "shmem" + *
      + * + * @see #getTransportName() + * @see #isSocketTransport() + * @see #isShmemTransport() + * @see #setRawArguments(String[]) + */ + public String getTransportType() { + return options.getProperty("transport", "socket"); + } + + /** + * Return transport name corresponding to the used JDWP transport type. + * + * @see #getTransportType() + */ + public String getTransportName() { + if (isSocketTransport()) { + return "dt_socket"; + } else if (isShmemTransport()) { + return "dt_shmem"; + } else { + throw new TestBug("Undefined transport type"); + } + } + + /** + * Return true if the used JDWP transport type is socket, + * either by specifying in command line or as a platform default transport. + * + * @see #getTransportType() + */ + public boolean isSocketTransport() { + String transport = getTransportType(); + return transport.equals("socket"); + } + + /** + * Return true if the used JDWP transport type is shmem, + * either by specifying in command line or as a platform default transport. + * + * @see #getTransportType() + */ + public boolean isShmemTransport() { + String transport = getTransportType(); + return transport.equals("shmem"); + } + + /** + * Return true if transport type is not actually specified. + * In this case getTransportType() returns some default transport kind. + * + * @see #getTransportType() + */ + public boolean isDefaultTransport() { + return options.getProperty("transport") == null; + } + + /** + * Create Log for debugee application using command line options. + */ + public Log createDebugeeLog() { + return new Log(System.err, this); + }; + + /** + * Create IOPipe for debugee application using command line options. + */ + public IOPipe createDebugeeIOPipe() { + return createDebugeeIOPipe(createDebugeeLog()); + }; + + /** + * Create IOPipe for debugee application using connection + * parameters from the command line and specify Log. + */ + public IOPipe createDebugeeIOPipe(Log log) { + return new IOPipe(this, log); + }; + + /** + * Check if an option is aloowed and has proper value. + * This method is invoked by parseArgumentss() + * + * @param option option name + * @param value string representation of value + * (could be an empty string too) + * null if this option has no value + * @return true if option is allowed and has proper value + * false if otion is not admissible + * + * @throws BadOption if option has an illegal value + * + * @see #parseArguments() + */ + protected boolean checkOption(String option, String value) { + + if(option.equals("traceAll")) + return true; + + // option with any string value + if (option.equals("debugee.vmkeys")) { + return true; + } + + // option with any nonempty string value + if (option.equals("test.host") + || option.equals("debugee.host") + || option.equals("debugee.vmkind") + || option.equals("debugee.vmhome") + || option.equals("transport.shname")) { + if (value.length() <= 0) { + throw new BadOption(option + ": cannot be an empty string"); + } + return true; + } + + // option with positive integer port value + if (option.equals("transport.port") + || option.equals("bind.port") + || option.equals("pipe.port")) { + try { + int number = Integer.parseInt(value); + if (number < 0) { + throw new BadOption(option + ": must be a positive integer"); + } + } catch (NumberFormatException e) { + throw new BadOption(option + ": must be an integer"); + } + return true; + } + + // options with enumerated values + + if (option.equals("debugee.suspend")) { + if ((!value.equals("yes")) + && (!value.equals("no")) + && (!value.equals("default"))) { + throw new BadOption(option + ": must be one of: " + + "yes, no, default"); + } + return true; + } + + if (option.equals("debugee.launch")) { + if ((!value.equals("local")) + && (!value.equals("remote")) + && (!value.equals("manual"))) { + throw new BadOption(option + ": must be one of: " + + "local, remote, manual " + value); + } + return true; + } + + if (option.equals("jvmdi.strict")) { + if ((!value.equals("yes")) + && (!value.equals("no")) + && (!value.equals("default"))) { + throw new BadOption(option + ": must be one of: " + + "yes, no, default"); + } + return true; + } + + if (option.equals("transport")) { + if ((!value.equals("socket")) + && (!value.equals("shmem"))) { + throw new BadOption(option + ": must be one of: " + + "socket, shmem"); + } + return true; + } + + if (option.equals("connector")) { + if ((!value.equals("attaching")) + && (!value.equals("listening"))) { + throw new BadOption(option + ": value must be one of: " + + "attaching, listening"); + } + return true; + } + + if (option.equals("transport.address")) { + if (!value.equals("dynamic")) { + throw new BadOption(option + ": must be only: " + + "dynamic"); + } + return true; + } + + return super.checkOption(option, value); + } + + /** + * Check if the values of all options are consistent. + * This method is invoked by parseArguments() + * + * @throws BadOption if options have inconsistent values + * + * @see #parseArguments() + */ + protected void checkOptions() { + super.checkOptions(); + } + + private String findFreePort() { + ServerSocket ss = null; + try { + ss = new ServerSocket(0); + return String.valueOf(ss.getLocalPort()); + } catch (IOException e) { + return null; + } finally { + try { + ss.close(); + } catch (Throwable t) { + // ignore + } + } + } + +} // DebugeeArgumentHandler diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeBinder.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeBinder.java new file mode 100644 index 00000000000..01c4df801ea --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeBinder.java @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jpda; + +import nsk.share.*; + +import java.io.*; +import java.net.*; +import java.util.*; + +/** + * This class provides debugger with ability to launch + * debuggee VM and to make connection to it using JDI connector or + * JDWP transport. + *

      + * The present version of Binder allows + * to launch debuggee VM either on local machine (local launch mode), + * or on remote host using BindServer utility + * (remote launch mode). Also there is an ability to launch + * debuggee VM manually as a separate process on local or remote machine + * (manual launch mode), which is usefull for debugging. + * All these launching modes are specified by command line option + * -debugee.launch recognized by DebugeeArgumentHandler. + *

      + * Binder also makes it possible to establish TCP/IP + * connection between debugger and debuggee throw IOPipe + * object. This connection allows debugger to communicate with debuggee + * by exchanging with synchronization messages and data. + *

      + * To launch debuggee VM and bind to it use bindToDebugee() + * method. This method construct mirror of debugee VM, represented by + * object of DebugeeProcess class or derived. This mirror object + * allows to control debuggee VM. + *

      + * See also nsk.share.jdi.Binder and nsk.share.jdwp.Binder + * classes which provide launching and binding to debuggee VM using specific + * JDI and JDWP features. + * + * @see DebugeeArgumentHandler + * @see DebugeeProcess + * @see IOPipe + * @see BindServer + * + * @see nsk.share.jdi.Binder + * @see nsk.share.jdwp.Binder + */ +public class DebugeeBinder extends Log.Logger implements Finalizable { + + private static final boolean IS_WINDOWS = System.getProperty("os.name") + .toLowerCase() + .startsWith("win"); + + public static int TRY_DELAY = 1000; // milliseconds + + public static int CONNECT_TIMEOUT = 1 * 60 * 1000; // milliseconds + public static int CONNECT_TRY_DELAY = 2 * 1000; // milliseconds + public static int CONNECT_TRIES = CONNECT_TIMEOUT / CONNECT_TRY_DELAY; + + public static int THREAD_TIMEOUT = 2 * CONNECT_TRY_DELAY; // milliseconds + public static int PING_TIMEOUT = 30 * 1000; // milliseconds + + public static int SOCKET_TIMEOUT = 2 * 1000; // milliseconds + public static int SOCKET_LINGER = 1; // milliseconds + + private static int TRACE_LEVEL_PACKETS = 10; + private static int TRACE_LEVEL_THREADS = 20; + private static int TRACE_LEVEL_ACTIONS = 30; + private static int TRACE_LEVEL_SOCKETS = 40; + private static int TRACE_LEVEL_IO = 50; + + /** + * Default message prefix for Binder object. + */ + public static final String LOG_PREFIX = "binder> "; + + private DebugeeArgumentHandler argumentHandler = null; + + /** + * Get version string. + */ + public static String getVersion () { + return "@(#)Binder.java %I% %E%"; + } + + // -------------------------------------------------- // + + private BindServerListener bindServerListener = null; + private ServerSocket pipeServerSocket = null; + + // -------------------------------------------------- // + + /** + * Incarnate new Binder obeying the given + * argumentHandler; and assign the given + * log. + */ + public DebugeeBinder (DebugeeArgumentHandler argumentHandler, Log log) { + super(log, LOG_PREFIX); + this.argumentHandler = argumentHandler; + Finalizer finalizer = new Finalizer(this); + finalizer.activate(); + } + + /** + * Get argument handler of this binder object. + */ + DebugeeArgumentHandler getArgumentHandler() { + return argumentHandler; + } + + // -------------------------------------------------- // + + /** + * Wait for given thread finished for THREAD_TIMEOUT timeout and + * interrupt this thread if not finished. + * + * @param thr thread to wait for + * @param logger to write log messages to + */ + public static void waitForThread(Thread thr, Log.Logger logger) { + waitForThread(thr, THREAD_TIMEOUT, logger); + } + + /** + * Wait for given thread finished for specified timeout and + * interrupt this thread if not finished. + * + * @param thr thread to wait for + * @param millisecs timeout in milliseconds + * @param logger to write log messages to + */ + public static void waitForThread(Thread thr, long millisecs, Log.Logger logger) { + if (thr != null) { + if (thr.isAlive()) { + try { + logger.trace(TRACE_LEVEL_THREADS, "Waiting for thread: " + thr.getName()); + thr.join(millisecs); + } catch (InterruptedException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure ("Thread interrupted while waiting for another thread:\n\t" + + e); + } finally { + if (thr.isAlive()) { + logger.trace(TRACE_LEVEL_THREADS, "Interrupting not finished thread: " + thr); + thr.interrupt(); + } + } + } + } + } + + + /** + * Make preperation for IOPipe connection before starting debugee VM process. + * May change options in the passed argumentHandler. + */ + protected void prepareForPipeConnection(DebugeeArgumentHandler argumentHandler) { + if (argumentHandler.isTransportAddressDynamic()) { + try { + pipeServerSocket = new ServerSocket(); + pipeServerSocket.setReuseAddress(false); + pipeServerSocket.bind(null); + + } catch (IOException e) { + e.printStackTrace(getOutStream()); + throw new Failure("Caught IOException while binding for IOPipe connection: \n\t" + + e); + } + + int port = pipeServerSocket.getLocalPort(); + argumentHandler.setPipePortNumber(port); + } + } + + /** + * Return already bound ServerSocket for IOPipe connection or null. + */ + protected ServerSocket getPipeServerSocket() { + return pipeServerSocket; + } + + /** + * Close ServerSocket used for IOPipeConnection if any. + */ + private void closePipeServerSocket() { + if (pipeServerSocket != null) { + try { + pipeServerSocket.close(); + } catch (IOException e) { + println("# WARNING: Caught IOException while closing ServerSocket used for IOPipe connection: \n\t" + + e); + } + } + } + + // -------------------------------------------------- // + + /** + * Make environment for launching JVM process. + */ + public String[] makeProcessEnvironment() { +/* + String env = new String[0]; + return env; + */ + return null; + } + + /** + * Launch process by the specified command line. + * + * @throws IOException if I/O error occured while launching process + */ + public Process launchProcess(String cmdLine) throws IOException { + String env[] = makeProcessEnvironment(); + return Runtime.getRuntime().exec(cmdLine, env); + } + + /** + * Launch process by the arguments array. + * + * @throws IOException if I/O error occured while launching process + */ + public Process launchProcess(String[] args) throws IOException { + String env[] = makeProcessEnvironment(); + return Runtime.getRuntime().exec(args, env); + } + + /** + * Make string representation of debuggee VM transport address according + * to current command line options. + */ + public String makeTransportAddress() { + String address = null; + if (argumentHandler.isSocketTransport()) { + if (argumentHandler.isListeningConnector()) { + address = argumentHandler.getTestHost() + + ":" + argumentHandler.getTransportPort(); + } else { + address = argumentHandler.getTransportPort(); + } + } else if (argumentHandler.isShmemTransport() ) { + address = argumentHandler.getTransportSharedName(); + } else { + throw new TestBug("Undefined transport type: " + + argumentHandler.getTransportType()); + } + return address; + } + + /** + * Make command line to launch debugee VM as a string using given quote symbol, + * using specified transportAddress for JDWP connection. + */ + public String makeCommandLineString(String classToExecute, String transportAddress, String quote) { + String[] args = makeCommandLineArgs(classToExecute, transportAddress); + return ArgumentParser.joinArguments(args, quote); + } + + /** + * Make command line to launch debugee VM as a string using given quote symbol. + */ + public String makeCommandLineString(String classToExecute, String quote) { + return makeCommandLineString(classToExecute, makeTransportAddress(), quote); + } + + /** + * Make command line to launch debugee VM as a string using default quote symbol, + * using specified transportAddress for JDWP connection. + */ +/* + public String makeCommandLineString(String classToExecute, String transportAddress) { + return makeCommandLineString(classToExecute, transportAddress, "\""); + } + */ + + /** + * Make command line to launch debugee VM as a string using default quote symbol. + */ +/* + public String makeCommandLineString(String classToExecute) { + return makeCommandLineString(classToExecute, makeTransportAddress()); + } + */ + + /** + * Make command line to launch debugee VM as an array of arguments, + * using specified transportAddress for JDWP connection. + */ + public String[] makeCommandLineArgs(String classToExecute, String transportAddress) { + Vector args = new Vector(); + + args.add(argumentHandler.getLaunchExecPath()); + + String javaOpts = argumentHandler.getLaunchOptions(); + if (javaOpts != null && javaOpts.length() > 0) { + StringTokenizer st = new StringTokenizer(javaOpts); + + while (st.hasMoreTokens()) { + args.add(st.nextToken()); + } + } + +/* + String classPath = System.getProperty("java.class.path"); + args.add("-classpath") + args.add(classPath); + */ + + args.add("-Xdebug"); + + String server; + if (argumentHandler.isAttachingConnector()) { + server = "y"; + } else { + server = "n"; + } + + String jdwpArgs = "-Xrunjdwp:" + + "server=" + server + + ",transport=" + argumentHandler.getTransportName() + + ",address=" + transportAddress; + + if (! argumentHandler.isDefaultJVMDIStrictMode()) { + if (argumentHandler.isJVMDIStrictMode()) + jdwpArgs += ",strict=y"; + else + jdwpArgs += ",strict=n"; + } + + args.add(jdwpArgs); + + if (classToExecute != null) { + StringTokenizer st = new StringTokenizer(classToExecute); + + while (st.hasMoreTokens()) { + args.add(st.nextToken()); + } + } + + String[] rawArgs = argumentHandler.getRawArguments(); + for (int i = 0; i < rawArgs.length; i++) { + String rawArg = rawArgs[i]; + // " has to be escaped on windows + if (IS_WINDOWS) { + rawArg = rawArg.replace("\"", "\\\""); + } + args.add(rawArg); + } + + String[] argsArray = new String[args.size()]; + for (int i = 0; i < args.size(); i++) { + argsArray[i] = (String) args.elementAt(i); + } + + return argsArray; + } + + /** + * Make command line to launch debugee VM as an array of arguments. + */ + public String[] makeCommandLineArgs(String classToExecute) { + return makeCommandLineArgs(classToExecute, makeTransportAddress()); + } + + /** + * Make connection to remote BindServer and start BindServerListener thread. + * + * @throws IOException if I/O error occured while connecting + */ + public void connectToBindServer(String taskID) { + if (bindServerListener != null) { + throw new Failure("Connection to BindServer already exists"); + } + try { + bindServerListener = new BindServerListener(this); + bindServerListener.setDaemon(true); + bindServerListener.connect(taskID); + bindServerListener.start(); + } catch (IOException e) { + e.printStackTrace(getOutStream()); + throw new Failure("Caught exception while connecting to BindServer:\n\t" + e); + } + } + + /** + * Split string into list of substrings using specified separator. + */ + private static String[] splitString(String givenString, String separator) { + Vector tmpList = new Vector(); + StringTokenizer tokenizer = new StringTokenizer(givenString, separator); + while(tokenizer.hasMoreTokens()) { + tmpList.add(tokenizer.nextToken()); + } + String[] list = new String[tmpList.size()]; + for (int i = 0; i < tmpList.size(); i++) { + list[i] = tmpList.elementAt(i); + } + return list; + } + + /** + * Send command to remote BindServer and receive reply. + * + * @throws IOException if I/O error occured while launching process + */ + public synchronized Object sendRemoteCommand(Object command) { + try { + bindServerListener.sendCommand(command); + Object reply = bindServerListener.getReply(); + return reply; + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Unexpected exception while sending command to BindServer:\n\t" + + e); + } + } + + /** + * Launch remote process using request to BindServer. + * + * @throws IOException if I/O error occured + */ + public void launchRemoteProcess(String[] args) throws IOException { + String pathSeparator = System.getProperty("path.separator"); + BindServer.LaunchDebugee command = + new BindServer.LaunchDebugee(args, + System.getProperty("file.separator"), + System.getProperty("user.dir"), + splitString(System.getProperty("java.library.path"), pathSeparator), + splitString(System.getProperty("java.class.path"), pathSeparator), + splitString(System.getProperty("java.library.path"), pathSeparator)); + + Object reply = sendRemoteCommand(command); + if (reply instanceof BindServer.OK) { + // do nothing + } else if (reply instanceof BindServer.RequestFailed) { + BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply; + throw new Failure("BindServer error: " + castedReply.reason); + } else { + throw new Failure("Wrong reply from BindServer: " + reply); + } + } + + /** + * Return exit status of the remotely launched process + * using request to BindServer. + */ + public int getRemoteProcessStatus () { + Object reply = sendRemoteCommand(new BindServer.DebugeeExitCode()); + if (reply instanceof BindServer.OK) { + BindServer.OK castedReply = (BindServer.OK)reply; + return (int)castedReply.info; + } else if (reply instanceof BindServer.CaughtException) { + BindServer.CaughtException castedReply = (BindServer.CaughtException)reply; + throw new IllegalThreadStateException(castedReply.reason); + } else if (reply instanceof BindServer.RequestFailed) { + BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply; + throw new Failure("BindServer error: " + castedReply.reason); + } else { + throw new Failure("Wrong reply from BindServer: " + reply); + } + } + + /** + * Check whether the remotely launched process has been terminated + * using request to BindServer. + */ + public boolean isRemoteProcessTerminated () { + try { + int value = getRemoteProcessStatus(); + return true; + } catch (IllegalThreadStateException e) { + return false; + } + } + + // ---------------------------------------------- // + + /** + * Kill the remotely launched process + * using request to BindServer. + */ + public void killRemoteProcess () { + Object reply = sendRemoteCommand(new BindServer.KillDebugee()); + if (reply instanceof BindServer.OK) { + return; + } else if (reply instanceof BindServer.RequestFailed) { + BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply; + throw new Failure("BindServer error: " + castedReply.reason); + } else { + throw new Failure("Wrong reply from BindServer: " + reply); + } + } + + /** + * Wait until the remotely launched process exits or crashes + * using request to BindServer. + */ + public int waitForRemoteProcess () { + + Object reply = sendRemoteCommand(new BindServer.WaitForDebugee(0)); + if (reply instanceof BindServer.OK) { + BindServer.OK castedReply = (BindServer.OK)reply; + return (int)castedReply.info; + } else if (reply instanceof BindServer.RequestFailed) { + BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply; + throw new Failure("BindServer error: " + castedReply.reason); + } else { + throw new Failure("Wrong reply from BindServer: " + reply); + } + } + + /** + * Close binder by closing all started threads. + */ + public void close() { + if (bindServerListener != null) { + bindServerListener.close(); + } + closePipeServerSocket(); + } + + /** + * Finalize binder by invoking close(). + * + * @throws Throwable if any throwable exception is thrown during finalization + */ + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + + /** + * Finalize binder at exit by invoking finalize(). + * + * @throws Throwable if any throwable exception is thrown during finalization + */ + public void finalizeAtExit() throws Throwable { + finalize(); + } + + /** + * Separate thread for listening connection from BindServer. + */ + private class BindServerListener extends Thread { + private SocketConnection connection = null; + private Log.Logger logger = null; + + /** List of received responses from BindServer. */ + private LinkedList replies = new LinkedList(); + + /** + * Make thread. + */ + public BindServerListener(Log.Logger logger) { + this.logger = logger; + } + + /** + * Establish connection to BindServer. + */ + public void connect(String taskID) throws IOException { + String host = argumentHandler.getDebugeeHost(); + int port = argumentHandler.getBindPortNumber(); + display("Connecting to BindServer: " + host + ":" + port); + connection = new SocketConnection(logger, "BindServer"); +// connection.setPingTimeout(DebugeeBinder.PING_TIMEOUT); + connection.attach(host, port); + handshake(taskID); + } + + /** + * Receive OK(version) from BindServer and check received version number. + */ + private void handshake(String taskID) { + // receive OK(version) + trace(TRACE_LEVEL_ACTIONS, "Waiting for initial OK(version) from BindServer"); + Object reply = connection.readObject(); + trace(TRACE_LEVEL_ACTIONS, "Got initial OK(version) from BindServer: " + reply); + if (reply instanceof BindServer.RequestFailed) { + BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply; + trace(TRACE_LEVEL_ACTIONS, "Reply is RequestFailed: throw Failure"); + throw new Failure("BindServer error: " + castedReply.reason); + } else if (reply instanceof BindServer.OK) { + BindServer.OK castedReply = (BindServer.OK)reply; + trace(TRACE_LEVEL_ACTIONS, "Reply is OK: check BindServer version"); + if (castedReply.info != BindServer.VERSION) { + throw new Failure("Wrong version of BindServer: " + castedReply.info + + " (expected: " + BindServer.VERSION + ")"); + } + display("Connected to BindServer: version " + castedReply.info); + } else { + trace(TRACE_LEVEL_ACTIONS, "Reply is unknown: throw Failure"); + throw new Failure("Wrong reply from BindServer: " + reply); + } + + // send TaskID(id) + try { + trace(TRACE_LEVEL_ACTIONS, "Sending TaskID(id) to BindServer"); + sendCommand(new BindServer.TaskID(taskID)); + trace(TRACE_LEVEL_ACTIONS, "Sent TaskID(id) to BindServer"); + } catch (IOException e) { + throw new Failure("Caught IOException while sending TaskID(id) to BindServer:\n\t" + + e); + } + } + + /** + * Check if thread is connected to BindServer. + */ + public boolean isConnected() { + return (connection != null && connection.isConnected()); + } + + /** + * Send a command to BindServer. + */ + public synchronized void sendCommand(Object command) throws IOException { + connection.writeObject(command); + } + + /** + * Receive response from BindServer. + */ + public Object getReply() { + synchronized (replies) { + while (replies.isEmpty()) { + if (!isConnected()) { + throw new Failure("No reply from BindServer: connection lost"); + } + try { + replies.wait(TRY_DELAY); + } catch (InterruptedException e) { + e.printStackTrace(getOutStream()); + throw new Failure("Thread interrupted while waiting for reply from BindServer:\n\t" + + e); + } + } + Object reply = replies.removeFirst(); + if (reply == null) { + throw new Failure("No reply from BindServer: connection lost"); + } + return reply; + } + } + + /** + * Add response object to the list of received responses. + */ + private void addReply(BindServer.Response reply) { + synchronized (replies) { + replies.add(reply); + replies.notifyAll(); + } + } + + /** + * Read packets from BindServer connection and + * notify waiting thread if response or IOPipe message received. + * Received lines of redirected streams are put into log. + */ + public void run() { + trace(TRACE_LEVEL_THREADS, "BindServerListener thread started"); + try { + for (;;) { + Object reply = connection.readObject(); + if (reply == null) { + break; + } else if (reply instanceof BindServer.Disconnect) { + reply = null; + trace(TRACE_LEVEL_ACTIONS, "Packet is Disconnect: close connection"); + break; + } else if (reply instanceof BindServer.RedirectedStream) { + BindServer.RedirectedStream castedReply = (BindServer.RedirectedStream)reply; + trace(TRACE_LEVEL_ACTIONS, "Packet is RedirectedStream: put message into log"); + log.println(castedReply.line); + } else if (reply instanceof BindServer.Response) { + BindServer.Response castedReply = (BindServer.Response)reply; + trace(TRACE_LEVEL_ACTIONS, "Packet is reply: notify all threads waiting for reply"); + addReply(castedReply); + } else { + trace(TRACE_LEVEL_ACTIONS, "Packet is unknown: throw Failure"); + throw new Failure("Wrong reply from BindServer: " + reply); + } + } + } catch (Exception e) { + e.printStackTrace(getOutStream()); + complain("Caught exception while reading packets from BindServer:\n\t" + e); + } finally { + closeConnection(); + addReply(null); + trace(TRACE_LEVEL_THREADS, "BindServerListener thread finished"); + } + } + + /** + * Send Disconnect command to BindServer. + */ + public void disconnect() { + if (connection == null) return; + try { + sendCommand(new BindServer.Disconnect()); + } catch (IOException e) { + display("Caught IOException while requesting disconnection with BindServer"); + } + } + + /** + * Close socket connection. + */ + public void closeConnection() { + if (connection != null) { + connection.close(); + } + } + + /** + * Wait for thread finished in the specified timeout or interrupt it. + */ + public void waitForThread(long millis) { + DebugeeBinder.waitForThread(this, millis, logger); + } + + /** + * Close this thread by waiting for it finishes or interrupt it + * and close socket connection. + */ + public void close() { + disconnect(); + waitForThread(DebugeeBinder.THREAD_TIMEOUT); + closeConnection(); + } + + } // BindServerListener + +} // DebugeeBinder diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeProcess.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeProcess.java new file mode 100644 index 00000000000..48ac15e0096 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeProcess.java @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jpda; + +import nsk.share.*; +import java.io.*; +import java.net.*; + +/** + * This class is used to control debugee VM process. + *

      + * Object of this class is constructed by DebugeeBinder + * and is used as a mirror of debugee VM process. + * It provides abilities to launch such process, + * redirect standard output streams, wait for process terminates + * or kill the process, and so on. + *

      + * This is an abstract class that declares abstract methods to control + * debugee VM process. + * Derived classes should implement these methods corresponding to the mode + * that the process should be started in (locally, remotely or manually). + *

      + * Particular derived classes nsk.share.jdi.Debugee and + * nsk.share.jdwp.Debugee provides additional abilities + * to control debugee VM using JDI or JDWP specific features. + * + * @see DebugeeBinder + * + * @see nsk.share.jdi.Debugee + * @see nsk.share.jdwp.Debugee + */ +abstract public class DebugeeProcess extends FinalizableObject { + + /** Default prefix for log messages. */ + public static final String LOG_PREFIX = "binder> "; + public static final String DEBUGEE_STDOUT_LOG_PREFIX = "debugee.stdout> "; + public static final String DEBUGEE_STDERR_LOG_PREFIX = "debugee.stderr> "; + + /** Messages prefix. */ + protected String prefix = LOG_PREFIX; + + /** Binder that creates this debugee process. */ + protected DebugeeBinder binder = null; + + /** Messages log from binder. */ + protected Log log = null; + + /** Communicational channel between debuger and debugee. */ + protected IOPipe pipe = null; + + /** Argument handler from binder. */ + protected DebugeeArgumentHandler argumentHandler = null; + + /** Need or not to check debuggee process termination at exit. */ + protected boolean checkTermination = false; + + /** Debugee VM process or null if not available. */ + protected Process process = null; + + /** Make new Debugee object for the given binder. */ + protected DebugeeProcess (DebugeeBinder binder) { + this.binder = binder; + this.log = binder.getLog(); + } + + /** + * Return already bound ServerSocket for IOPipe connection or null. + */ + protected ServerSocket getPipeServerSocket() { + return binder.getPipeServerSocket(); + } + + /** Return DebugeeArgumentHandler of the debugee object. */ + public DebugeeArgumentHandler getArgumentHandler() { + return binder.getArgumentHandler(); + } + + /** Return Log of the debugee object. */ + public Log getLog() { + return log; + } + + /** Return Process object associated with debugee VM or null. */ + public Process getProcess() { + return process; + } + + // --------------------------------------------------- // + + /** Created and return new IOPipe channel to the debugee VM. */ + public IOPipe createIOPipe() { + if (pipe != null) { + throw new TestBug("IOPipe channel is already created"); + } + pipe = new IOPipe(this); + return pipe; + } + + /** Return IOPipe channel or null if not yet ctreated. */ + public IOPipe getIOPipe() { + return pipe; + } + + /** Receive and return signal from the debugee VM via IOPipe channel. + * + * @throws TestBug if IOPipe channel is not created + */ + public String receiveSignal() { + if ( pipe == null ) + throw new TestBug("IOPipe channel is not initialized"); + return pipe.readln(); + } + + /** Receive an expected signal from the debugee VM via IOPipe channel. + * + * @throws Failure if received signal is not equal to the expected one + * @throws TestBug if IOPipe channel is not created + */ + public void receiveExpectedSignal(String signal) { + String line = receiveSignal(); + if (line == null || !line.equals(signal)) + throw new Failure("Received unexpected signal from debugee: " + line); + display("Received expected signal from debugee: " + signal); + } + + /** Send signal to the debugee VM via IOPipe channel. + * + * @throws TestBug if IOPipe channel is not defined created. + */ + public void sendSignal(String signal) { + if (pipe == null) + throw new TestBug("IOPipe channel is not initialized"); + pipe.println(signal); + } + + + // --------------------------------------------------- // + + /** Wait until the debugee VM shutdown or crash. */ + abstract protected int waitForDebugee () throws InterruptedException; + + /** Kill the debugee VM. */ + abstract protected void killDebugee (); + + /** Check whether the debugee VM has been terminated. */ + abstract public boolean terminated (); + + /** Return the debugee VM exit status. */ + abstract public int getStatus (); + + /** Get a pipe to write to the debugee's stdin stream. */ + abstract protected OutputStream getInPipe (); + + /** Get a pipe to read the debugee's stdout stream. */ + abstract protected InputStream getOutPipe (); + + /** Get a pipe to read the debugee's stderr stream. */ + abstract protected InputStream getErrPipe (); + + // --------------------------------------------------- // + + /** + * Wait until the debugee VM shutdown or crash, + * and let finish its stdout, stderr, and stdin + * redirectors (if any). + * + * @return Debugee process exit code. + * @see #waitForRedirectors(long) + */ + public int waitFor () { + long timeout = binder.getArgumentHandler().getWaitTime() * 60 * 1000; + int exitCode = 0; + try { + exitCode = waitForDebugee(); + } catch (InterruptedException ie) { + ie.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while waiting for debuggee process: \n\t" + ie); + } + waitForRedirectors(timeout); + if (process != null) { + process.destroy(); + } + return exitCode; + } + + /** + * Wait until the debugee VM redirectors to complete for specified timeout. + * + * @see #waitFor() + */ + public void waitForRedirectors (long timeout) { + try { + if (stdinRedirector != null) { + if (stdinRedirector.isAlive()) { + stdinRedirector.join(timeout); + if (stdinRedirector.isAlive()) { + log.complain("Timeout for waiting STDIN redirector exceeded"); + stdinRedirector.interrupt(); + } + } + stdinRedirector = null; + }; + if (stdoutRedirector != null) { + if (stdoutRedirector.isAlive()) { + stdoutRedirector.join(timeout); + if (stdoutRedirector.isAlive()) { + log.complain("Timeout for waiting STDOUT redirector exceeded"); + stdoutRedirector.interrupt(); + } + } + stdoutRedirector = null; + }; + if (stderrRedirector != null) { + if (stderrRedirector.isAlive()) { + stderrRedirector.join(timeout); + if (stderrRedirector.isAlive()) { + log.complain("Timeout for waiting STDERR redirector exceeded"); + stderrRedirector.interrupt(); + } + } + stderrRedirector = null; + }; + } catch (InterruptedException ie) { + ie.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while waiting for debuggee output redirectors: \n\t" + + ie); + } + } + + // --------------------------------------------------- // + + /** + * Get a pipe to write to the debugee's stdin stream, + * or throw TestBug exception is redirected. + */ + final public OutputStream getStdin () { + if (stdinRedirector != null) + throw new TestBug("Debugee's stdin is redirected"); + return getInPipe(); + } + + /** + * Get a pipe to read the debugee's stdout stream, + * or throw TestBug exception is redirected. + */ + final public InputStream getStdout () { + if (stdoutRedirector != null) + throw new TestBug("Debugee's stdout is redirected"); + return getOutPipe(); + } + + /** + * Get a pipe to read the debugee's stderr stream, + * or throw TestBug exception is redirected. + */ + final public InputStream getStderr () { + if (stderrRedirector != null) + throw new TestBug("Debugee's stderr is redirected"); + return getErrPipe(); + } + + // --------------------------------------------------- // + + private IORedirector stdoutRedirector = null; + private IORedirector stderrRedirector = null; + private IORedirector stdinRedirector = null; + +// /** +// * Start a thread redirecting the given in stream +// * to the debugee's stdin. If the debugee's stdin was already +// * redirected, the TestBug exception is thrown. +// */ +// final public void redirectStdin(InputStream in) { +// if (stdinRedirector != null) +// throw new TestBug("the debugee's stdin is already redirected"); +// stdinRedirector = new IORedirector(in,getInPipe()); +// stdinRedirector.setName("IORedirector for stdin"); +// stdinRedirector.setDaemon(true); +// stdinRedirector.start(); +// } + + /** + * Start thread redirecting the debugee's stdout to the + * given out stream. If the debugee's stdout + * was already redirected, the TestBug exception is thrown. + * + * @deprecated Use redirectStdout(Log, String) instead. + */ + public void redirectStdout(OutputStream out) { + if (stdoutRedirector != null) { + return; + } +// throw new TestBug("Debugee's stdout is already redirected"); + stdoutRedirector = new IORedirector(getOutPipe(),out); + stdoutRedirector.setPrefix(DEBUGEE_STDOUT_LOG_PREFIX); + stdoutRedirector.setName("IORedirector for stdout"); + stdoutRedirector.setDaemon(true); + stdoutRedirector.start(); + } + + /** + * Start thread redirecting the debugee's stdout to the + * given Log. If the debugee's stdout + * was already redirected, the TestBug exception is thrown. + */ + public void redirectStdout(Log log, String prefix) { + if (stdoutRedirector != null) { +// stdoutRedirector.setPrefix(prefix); + return; +// throw new TestBug("the debugee's stdout is already redirected"); + } + stdoutRedirector = new IORedirector(new BufferedReader(new InputStreamReader(getOutPipe())), log, prefix); + stdoutRedirector.setName("IORedirector for stdout"); + stdoutRedirector.setDaemon(true); + stdoutRedirector.start(); + } + + /** + * Start thread redirecting the debugee's stderr to the + * given err stream. If the debugee's stderr + * was already redirected, the TestBug exception is thrown. + * + * @deprecated Use redirectStderr(Log, String) instead. + */ + public void redirectStderr(OutputStream err) { + if (stderrRedirector != null) { + return; + } +// throw new TestBug("Debugee's stderr is already redirected"); + stderrRedirector = new IORedirector(getErrPipe(),err); + stderrRedirector.setPrefix(DEBUGEE_STDERR_LOG_PREFIX); + stdoutRedirector.setName("IORedirector for stderr"); + stderrRedirector.setDaemon(true); + stderrRedirector.start(); + } + + /** + * Start thread redirecting the debugee's stderr to the + * given Log. If the debugee's stderr + * was already redirected, the TestBug exception is thrown. + */ + public void redirectStderr(Log log, String prefix) { + if (stderrRedirector != null) { +// stderrRedirector.setPrefix(prefix); + return; +// throw new TestBug("Debugee's stderr is already redirected"); + } + stderrRedirector = new IORedirector(new BufferedReader(new InputStreamReader(getErrPipe())), log, prefix); + stdoutRedirector.setName("IORedirector for stderr"); + stderrRedirector.setDaemon(true); + stderrRedirector.start(); + } + + /** + * Start thread redirecting the debugee's stdout/stderr to the + * given Log using standard prefixes. + * If the debugee's stdout/stderr were already redirected, + * the TestBug exception is thrown. + */ + public void redirectOutput(Log log) { + redirectStdout(log, "debugee.stdout> "); + redirectStderr(log, "debugee.stderr> "); + } + // --------------------------------------------------- // + + /** + * Kill the debugee VM if it is not terminated yet. + * + * @throws Throwable if any throwable exception is thrown during finalization + */ + public void close() { + if (checkTermination) { + if (!terminated()) { + complain("Debugee VM has not exited correctly: trying to kill it"); + killDebugee(); + } + checkTermination = false; + } + } + + // --------------------------------------------------- // + + /** + * Display log message with prefix. + */ + protected void display(String message) { + log.display(prefix + message); + } + + /** + * Complain about error with specified message. + */ + protected void complain(String message) { + log.complain(prefix + message); + } + + /** + * Finalize debuggee VM wrapper by invoking close(). + * + * @throws Throwable if any throwable exception is thrown during finalization + */ + protected void finalize() throws Throwable { + close(); + super.finalize(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ForceEarlyReturnTestThread.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ForceEarlyReturnTestThread.java new file mode 100644 index 00000000000..e43c6801f0e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ForceEarlyReturnTestThread.java @@ -0,0 +1,1038 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// THIS TEST IS LINE NUMBER SENSITIVE + +package nsk.share.jpda; + +import java.net.*; +import nsk.share.*; + +// ForceEarlyReturnTestThread intended for testing ForceEarlyReturn functionality. +// +// ForceEarlyReturnTestThread contains test methods with different return type +// (types corresponds to subclasses of com.sun.jdi.Value or JDWP type identifiers). +// Debugger VM should set breakpoint on line log("...") and when test thread stop at breakpoint call +// forceEarlyReturn(), so instructions after breakpoint shouldn't be executed(unexpectedMethod() shouldn't be called) +// When started thread executes all test methods in order assigned in 'testedTypesNames' array. +// It is possible to run this thread in 'testThread' mode, in this mode thread check that values returned from +// test methods equals to those that should be returned through forceEarlyReturn, and no +// instructions was executed in called method after force return (finally blocks are not executed too). +// In non-testThread mode thread check that values returned from test methods was not changed. +public class ForceEarlyReturnTestThread +extends Thread +{ + void VoidMethod() + { + try + { + log("in void method"); // breakpointLines[0] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + } + + boolean BooleanMethod() + { + try + { + log("in boolean method"); // breakpointLines[1] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedBooleanValue; + } + + byte ByteMethod() + { + try + { + log("in byte method"); // breakpointLines[2] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedByteValue; + } + + short ShortMethod() + { + try + { + log("in short method"); // breakpointLines[3] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedShortValue; + } + + char CharMethod() + { + try + { + log("in char method"); // breakpointLines[4] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedCharValue; + } + + int IntMethod() + { + try + { + log("in int method"); // breakpointLines[5] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedIntValue; + } + + long LongMethod() + { + try + { + log("in long method"); // breakpointLines[6] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedLongValue; + } + + float FloatMethod() + { + try + { + log("in float method"); // breakpointLines[7] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedFloatValue; + } + + double DoubleMethod() + { + try + { + log("in double method"); // breakpointLines[8] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedDoubleValue; + } + + Object[] ObjectArrayMethod() + { + try + { + log("in object array method"); // breakpointLines[9] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedObjectArrayValue; + } + + String StringMethod() + { + try + { + log("in string method"); // breakpointLines[10] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedStringValue; + } + + Thread ThreadMethod() + { + try + { + log("in thread method"); // breakpointLines[11] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedThreadValue; + } + + ThreadGroup ThreadGroupMethod() + { + try + { + log("in thread group method"); // breakpointLines[12] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedThreadGroupValue; + } + + Class ClassObjectMethod() + { + try + { + log("in class object method"); // breakpointLines[13] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedClassObjectValue; + } + + ClassLoader ClassLoaderMethod() + { + try + { + log("in class loader method"); // breakpointLines[14] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedClassLoaderValue; + } + + Object ObjectMethod() + { + try + { + log("in object method"); // breakpointLines[15] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedObjectValue; + } + + Boolean BooleanWrapperMethod() + { + try + { + log("in boolean wrapper method"); // breakpointLines[16] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedBooleanWrapperValue; + } + + Byte ByteWrapperMethod() + { + try + { + log("in byte wrapper method"); // breakpointLines[17] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedByteWrapperValue; + } + + Short ShortWrapperMethod() + { + try + { + log("in short wrapper method"); // breakpointLines[18] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedShortWrapperValue; + } + + Character CharWrapperMethod() + { + try + { + log("in char wrapper method"); // breakpointLines[19] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedCharWrapperValue; + } + + Integer IntWrapperMethod() + { + try + { + log("in int wrapper method"); // breakpointLines[20] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedIntWrapperValue; + } + + Long LongWrapperMethod() + { + try + { + log("in long wrapper method"); // breakpointLines[21] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedLongWrapperValue; + } + + Float FloatWrapperMethod() + { + try + { + log("in float wrapper method"); // breakpointLines[22] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedFloatWrapperValue; + } + + Double DoubleWrapperMethod() + { + try + { + log("in double wrapper method"); // breakpointLines[23] + } + finally + { + unexpectedMethod(); + } + + unexpectedMethod(); + + return unexpectedDoubleWrapperValue; + } + + private void log(String message) + { + log.display(currentThread().getName() + ": " + message); + } + + private void logError(String message) + { + log.complain(currentThread().getName() + ": " + message); + } + + // values which should be passed in forceEarlyReturn(): + + public static boolean expectedBooleanValue = Boolean.TRUE; + public static byte expectedByteValue = Byte.MAX_VALUE; + public static char expectedCharValue = Character.MAX_VALUE; + public static short expectedShortValue = Short.MAX_VALUE; + public static int expectedIntValue = Integer.MAX_VALUE; + public static long expectedLongValue = Long.MAX_VALUE; + public static float expectedFloatValue = Float.MAX_VALUE; + public static double expectedDoubleValue = Double.MAX_VALUE; + public static Object[] expectedObjectArrayValue = new Object[1000]; + public static Thread expectedThreadValue = new Thread(); + public static ThreadGroup expectedThreadGroupValue = new ThreadGroup("Expected thread group"); + public static Class expectedClassObjectValue = ForceEarlyReturnTestThread.class; + public static ClassLoader expectedClassLoaderValue = new URLClassLoader(new URL[]{}); + public static String expectedStringValue = "EXPECTED STRING"; + public static Object expectedObjectValue = new Object(); + public static Boolean expectedBooleanWrapperValue = new Boolean(Boolean.TRUE); + public static Byte expectedByteWrapperValue = new Byte(Byte.MAX_VALUE); + public static Character expectedCharWrapperValue = new Character(Character.MAX_VALUE); + public static Short expectedShortWrapperValue = new Short(Short.MAX_VALUE); + public static Integer expectedIntWrapperValue = new Integer(Integer.MAX_VALUE); + public static Long expectedLongWrapperValue = new Long(Long.MAX_VALUE); + public static Float expectedFloatWrapperValue = new Float(Float.MAX_VALUE); + public static Double expectedDoubleWrapperValue = new Double(Double.MAX_VALUE); + + // values which should be returned from test methods without forceEarlyReturn(): + + public static boolean unexpectedBooleanValue = Boolean.FALSE; + public static byte unexpectedByteValue = 0; + public static char unexpectedCharValue = 0; + public static short unexpectedShortValue = 0; + public static int unexpectedIntValue = 0; + public static long unexpectedLongValue = 0; + public static float unexpectedFloatValue = 0; + public static double unexpectedDoubleValue = 0; + public static Object[] unexpectedObjectArrayValue = new Object[1000]; + public static String unexpectedStringValue = "UNEXPECTED STRING"; + public static Thread unexpectedThreadValue = new Thread(); + public static ThreadGroup unexpectedThreadGroupValue = new ThreadGroup("Unexpected thread group"); + public static Class unexpectedClassObjectValue = Object.class; + public static ClassLoader unexpectedClassLoaderValue = new URLClassLoader(new URL[]{}); + public static Object unexpectedObjectValue = new Object(); + public static Boolean unexpectedBooleanWrapperValue = new Boolean(Boolean.FALSE); + public static Byte unexpectedByteWrapperValue = new Byte((byte)0); + public static Character unexpectedCharWrapperValue = new Character((char)0); + public static Short unexpectedShortWrapperValue = new Short((short)0); + public static Integer unexpectedIntWrapperValue = new Integer(0); + public static Long unexpectedLongWrapperValue = new Long(0); + public static Float unexpectedFloatWrapperValue = new Float(0); + public static Double unexpectedDoubleWrapperValue = new Double(0); + + public static int[] breakpointLines = { + 49, + 63, + 79, + 95, + 111, + 127, + 143, + 159, + 175, + 191, + 207, + 223, + 239, + 255, + 271, + 287, + 303, + 319, + 335, + 351, + 367, + 383, + 399, + 415}; + + /* Invalid data for ForceEarlyReturn, needed to check is ForceEarlyReturn complies with following part of specification: + * Object values must be assignment compatible with the method return type + * (This implies that the method return type must be loaded through the enclosing class's class loader). + * Primitive values must be either assignment compatible with the method return type or must + * be convertible to the variable type without loss of information. + */ + public static boolean invalidVoidValue = Boolean.TRUE; + public static boolean invalidObjectValue = Boolean.TRUE; + public static byte invalidBooleanValue = Byte.MAX_VALUE; + public static short invalidByteValue = Short.MAX_VALUE; + public static char invalidShortValue = Character.MAX_VALUE; + public static int invalidCharValue = Integer.MAX_VALUE; + public static long invalidIntValue = Long.MAX_VALUE; + public static float invalidLongValue = Float.MAX_VALUE; + public static double invalidFloatValue = Double.MAX_VALUE; + public static Object[] invalidDoubleValue = new Object[1000]; + public static String invalidObjectArrayValue = "EXPECTED STRING"; + public static Thread invalidStringValue = new Thread("Invalid thread"); + public static ThreadGroup invalidThreadValue = new ThreadGroup("Invalid thread group"); + public static Class invalidThreadGroupValue = ForceEarlyReturnTestThread.class; + public static ClassLoader invalidClassObjectValue = new URLClassLoader(new URL[]{}); + public static Object invalidClassLoaderValue = new Object(); + public static Byte invalidBooleanWrapperValue = new Byte(Byte.MAX_VALUE); + public static Short invalidByteWrapperValue = new Short(Short.MAX_VALUE); + public static Character invalidShortWrapperValue = new Character(Character.MAX_VALUE); + public static Integer invalidCharWrapperValue = new Integer(Integer.MAX_VALUE); + public static Long invalidIntWrapperValue = new Long(Long.MAX_VALUE); + public static Float invalidLongWrapperValue = new Float(Float.MAX_VALUE); + public static Double invalidFloatWrapperValue = new Double(Double.MAX_VALUE); + public static Object[] invalidDoubleWrapperValue = new Object[1000]; + + // names of tested types, this names can be used to derive names of tested methods(typeName + 'Method'), + // names of fields containing predefined data to be returned through ForceEarlyReturn('expected' + typeName + 'Value'), + // names of fields containing invalid data for ForceEarlyReturn(needed to check is ForceEarlyReturn complies with its specification('invalid' + typeName + 'Value')) + public static String testedTypesNames[] = + { + "Void", + "Boolean", + "Byte", + "Short", + "Char", + "Int", + "Long", + "Float", + "Double", + "ObjectArray", + "String", + "Thread", + "ThreadGroup", + "ClassObject", + "ClassLoader", + "Object", + "BooleanWrapper", + "ByteWrapper", + "ShortWrapper", + "CharWrapper", + "IntWrapper", + "LongWrapper", + "FloatWrapper", + "DoubleWrapper", + }; + + private Log log; + + // is forceEarlyReturn would called for this thread + private boolean isTestThread; + + // how many times call all test methods (zero means infinite execution) + private int iterationsNumber = 1; + + // test thread wait on 'startExecutionWicket' in beginning of run() + private Wicket startExecutionWicket = new Wicket(); + + private boolean success = true; + + public ForceEarlyReturnTestThread(Log log, boolean isTestThread, int iterationNumber) + { + this.log = log; + this.isTestThread = isTestThread; + + this.iterationsNumber = iterationNumber; + } + + private volatile boolean stopExecution; + + public void stopExecution() + { + stopExecution = true; + } + + public void startExecuion() + { + startExecutionWicket.unlockAll(); + } + + public void run() + { + // first, debuggee VM starts and suspends test threads to let debugger initialize breakpoints + startExecutionWicket.waitFor(); + + int iterationCount = 0; + + // test thread executes test methods 'iterationNumber' times + // non-test thread execute until not interrupted + // (iterationsNumber = 0 means infinite execution) + while(!stopExecution && (!isTestThread || ((iterationsNumber == 0) || (iterationCount++ < iterationsNumber)))) + { + // execute test methods in order given in 'testMethodsNames' array + for(int i = 0; (i < testedTypesNames.length) && !stopExecution; i++) + { + executeMethod(testedTypesNames[i] + "Method"); + + /* + * Small delay was inserted because of if test starts several ForceEarlyReturnTestThreads + * with parameter isTestThread = false, these threads may consume too many CPU time and test + * execution will be very slow + */ + if (!isTestThread) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + logError("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + success = false; + } + } + } + } + + log("Test thread exit"); + } + + // execute test method and check that correct value is returned + private void executeMethod(String methodName) + { + if(methodName.equals("VoidMethod")) + { + VoidMethod(); + } + if(methodName.equals("BooleanMethod")) + { + boolean result = BooleanMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + boolean expectedResult; + + expectedResult = isTestThread ? expectedBooleanValue : unexpectedBooleanValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ByteMethod")) + { + byte result = ByteMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + byte expectedResult; + + expectedResult = isTestThread ? expectedByteValue : unexpectedByteValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("CharMethod")) + { + char result = CharMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + char expectedResult; + + expectedResult = isTestThread ? expectedCharValue : unexpectedCharValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ShortMethod")) + { + short result = ShortMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + short expectedResult; + + expectedResult = isTestThread ? expectedShortValue : unexpectedShortValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("IntMethod")) + { + int result = IntMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + int expectedResult; + + expectedResult = isTestThread ? expectedIntValue : unexpectedIntValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("LongMethod")) + { + long result = LongMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + long expectedResult; + + expectedResult = isTestThread ? expectedLongValue : unexpectedLongValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("FloatMethod")) + { + float result = FloatMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + float expectedResult; + + expectedResult = isTestThread ? expectedFloatValue : unexpectedFloatValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("DoubleMethod")) + { + double result = DoubleMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + double expectedResult; + + expectedResult = isTestThread ? expectedDoubleValue : unexpectedDoubleValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("StringMethod")) + { + String result = StringMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + String expectedResult; + + expectedResult = isTestThread ? expectedStringValue : unexpectedStringValue; + + if(!result.equals(expectedResult)) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ObjectMethod")) + { + Object result = ObjectMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Object expectedResult; + + expectedResult = isTestThread ? expectedObjectValue : unexpectedObjectValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ObjectArrayMethod")) + { + Object[] result = ObjectArrayMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Object[] expectedResult; + + expectedResult = isTestThread ? expectedObjectArrayValue : unexpectedObjectArrayValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ThreadMethod")) + { + Thread result = ThreadMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Thread expectedResult; + + expectedResult = isTestThread ? expectedThreadValue : unexpectedThreadValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ThreadGroupMethod")) + { + ThreadGroup result = ThreadGroupMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + ThreadGroup expectedResult; + + expectedResult = isTestThread ? expectedThreadGroupValue : unexpectedThreadGroupValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ClassObjectMethod")) + { + Class result = ClassObjectMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Class expectedResult; + + expectedResult = isTestThread ? expectedClassObjectValue : unexpectedClassObjectValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ClassLoaderMethod")) + { + ClassLoader result = ClassLoaderMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + ClassLoader expectedResult; + + expectedResult = isTestThread ? expectedClassLoaderValue : unexpectedClassLoaderValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("BooleanWrapperMethod")) + { + Boolean result = BooleanWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Boolean expectedResult; + + expectedResult = isTestThread ? expectedBooleanWrapperValue : unexpectedBooleanWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ByteWrapperMethod")) + { + Byte result = ByteWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Byte expectedResult; + + expectedResult = isTestThread ? expectedByteWrapperValue : unexpectedByteWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("ShortWrapperMethod")) + { + Short result = ShortWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Short expectedResult; + + expectedResult = isTestThread ? expectedShortWrapperValue : unexpectedShortWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("CharWrapperMethod")) + { + Character result = CharWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Character expectedResult; + + expectedResult = isTestThread ? expectedCharWrapperValue : unexpectedCharWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("IntWrapperMethod")) + { + Integer result = IntWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Integer expectedResult; + + expectedResult = isTestThread ? expectedIntWrapperValue : unexpectedIntWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("LongWrapperMethod")) + { + Long result = LongWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Long expectedResult; + + expectedResult = isTestThread ? expectedLongWrapperValue : unexpectedLongWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("FloatWrapperMethod")) + { + Float result = FloatWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Float expectedResult; + + expectedResult = isTestThread ? expectedFloatWrapperValue : unexpectedFloatWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + if(methodName.equals("DoubleWrapperMethod")) + { + Double result = DoubleWrapperMethod(); + + // log(Thread.currentThread() + ": result of " + methodName + ": " + result); + + Double expectedResult; + + expectedResult = isTestThread ? expectedDoubleWrapperValue : unexpectedDoubleWrapperValue; + + if(result != expectedResult) + { + logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult); + success = false; + } + } + } + + // method which shouldn't be executed in test thread + void unexpectedMethod() + { + if(isTestThread) + { + success = false; + logError("unexpected code is executed after forceEarlyReturn"); + } + } + + public boolean getSuccess() + { + return success; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/IOPipe.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/IOPipe.java new file mode 100644 index 00000000000..e6d242d9130 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/IOPipe.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jpda; + +import nsk.share.*; + +/** + * This class implements communicational channel between + * debugger and debugee used for synchronization and data exchange. + * This channel is based on TCP/IP sockets and works in all + * modes (local, remote and manual). In a remote mode + * connection to BindServer is used for redirecting IOPipe messages. + * In all other modes direct TCP/IP coonnection between two VMs is used. + * + * @see BindServer + */ +public class IOPipe extends SocketIOPipe { + + public static final byte PORTS_COUNT = 10; + public static final byte NO_PORTS = 0; + + public static final String PIPE_LOG_PREFIX = "IOPipe> "; + + private DebugeeProcess debugee; + + /** + * Make IOPipe at debugee's side. + * + * @deprecated Use DebugeeArgumentHandler.createDebugeeIOPipe(Log) instead. + * + * @see DebugeeArgumentHandler#createDebugeeIOPipe(Log) + */ + public IOPipe(DebugeeArgumentHandler argumentHandler, Log log) { + this(log, getTestHost(argumentHandler), argumentHandler.getPipePortNumber(), + (long)argumentHandler.getWaitTime() * 60 * 1000, false); + } + + /** + * Make IOPipe at debugger's side + * with given Debugee mirror. + * + * @deprecated Use Debugee.createIOPipe() instead. + */ + public IOPipe(DebugeeProcess debugee) { + this(debugee.getLog(), + debugee.getArgumentHandler().getDebugeeHost(), + debugee.getArgumentHandler().getPipePortNumber(), + (long)debugee.getArgumentHandler().getWaitTime() * 60 * 1000, + true); + + this.debugee = debugee; + } + + /** + * Make general IOPipe object with specified parameters. + */ + protected IOPipe(Log log, String host, int port, long timeout, boolean listening) { + super("IOPipe", log, PIPE_LOG_PREFIX, host, port, timeout, listening); + } + + protected void connect() { + if (listening) { + setServerSocket(debugee.getPipeServerSocket()); + setConnectingProcess(debugee.getProcess()); + } + + super.connect(); + } + + /** + * Get appropriate test host name relying on the provided argumnets. + */ + private static String getTestHost(DebugeeArgumentHandler argumentHandler) { + return argumentHandler.getTestHost(); + } + +} // IOPipe diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java new file mode 100644 index 00000000000..6ca63cb0f0f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.jpda; + +import java.io.*; +import java.net.*; + +import nsk.share.*; + +/** + * This class implements basic connection channel via TCP/IP sockets. + */ +class BasicSocketConnection { + + protected static int TRACE_LEVEL_PACKETS = 10; + + protected static int TRACE_LEVEL_THREADS = 20; + + protected static int TRACE_LEVEL_ACTIONS = 30; + + protected static int TRACE_LEVEL_SOCKETS = 40; + + protected static int TRACE_LEVEL_IO = 50; + + protected String name = null; + + protected ServerSocket serverSocket = null; + + protected Socket socket = null; + + protected InputStream sin = null; + + protected OutputStream sout = null; + + protected Process connectingProcess = null; + + protected volatile boolean connected = false; + + protected volatile boolean closed = false; + + protected volatile boolean connectionClosed = false; + + protected volatile boolean shouldStop = false; + + protected Log.Logger logger = null; + + /** + * Make an empty connection with specified name. + * + * @param logger + * Logger object for printing log messages + * @param name + * connection name + */ + public BasicSocketConnection(Log.Logger logger, String name) { + this.logger = logger; + this.name = name; + } + + /** + * Try to bind connection to the local port. + * + * @param port + * port number to bind to + * + * @throws IOException + * if error occured while binding + */ + protected void tryBind(int port) throws IOException { + logger.trace(TRACE_LEVEL_IO, "Binding for " + name + " connection to port: " + port); + serverSocket = new ServerSocket(port, 1); + logger.trace(TRACE_LEVEL_IO, "Bound for " + name + " connection to port: " + port); + } + + /** + * Bind connection to the local port for specified timeout. + * + * @param port + * port number to bind to + * @param timeout + * binding timeout in milliseconds + * + * @throws Failure + * if error ocured while binding + */ + protected void bind(int port, long timeout) { + BindException bindException = null; + long timeToFinish = System.currentTimeMillis() + timeout; + for (long i = 0; !shouldStop && (timeout == 0 || System.currentTimeMillis() < timeToFinish); i++) { + try { + tryBind(port); + return; + } catch (BindException e) { + bindException = e; + logger.display("Attempt #" + i + " to bind to port " + port + " failed:\n\t" + e); + try { + Thread.sleep(DebugeeBinder.CONNECT_TRY_DELAY); + } catch (InterruptedException ie) { + ie.printStackTrace(logger.getOutStream()); + throw new Failure("Thread interrupted while binding for " + name + " connection to port " + port + ":\n\t" + ie); + } + } catch (IOException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught IOException while binding for " + name + " connection to port " + port + ":\n\t" + e); + } + } + throw new Failure("Unable to bind for " + name + " connection to port " + port + " for " + timeout + "ms timeout:\n\t" + bindException); + } + + /** + * Accept connection at the bound port for specified timeout. + * + * @param timeout + * accepting timeout in milliseconds + * + * @throws Failure + * if error occured while accepting connection + */ + public void accept(long timeout) { + int port = serverSocket.getLocalPort(); + logger.trace(TRACE_LEVEL_IO, "Listening for " + name + " connection at port: " + port); + socket = null; + try { + if (timeout > Integer.MAX_VALUE) { + throw new TestBug("Too large timeout long value: " + timeout + " (can't cast it to int)"); + } + + serverSocket.setSoTimeout((int)timeout); + + long waitStartTime = System.currentTimeMillis(); + + /* + * We found that sometimes (very rarely) on Solaris ServerSocket.accept() throws InterruptedIOException + * even if connection timeout (specified through ServerSocket.setSoTimeout) didn't expire. + * Following code tries to catch such case and call ServerSocket.accept() while timeout didn't expire. + */ + do { + try { + socket = serverSocket.accept(); + logger.trace(TRACE_LEVEL_IO, "Accepted " + name + " connection at port: " + port); + } catch (InterruptedIOException e) { + long interruptTime = System.currentTimeMillis(); + long waitTime = interruptTime - waitStartTime; + + logger.display("Caught InterruptedIOException. Wait start time: " + waitStartTime + ", exception was thrown at: " + + interruptTime + ", wait time: " + (interruptTime - waitStartTime) + ", actual timeout: " + timeout); + + // if waitTime was too small call ServerSocket.accept() one more time + if (!shouldStop && (waitTime < (timeout / 2))) { + logger.display("InterruptedIOException was thrown too early, trying to call ServerSocket.accept() one more time"); + continue; + } else { + if (!shouldStop) { + logger.complain("Caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e); + throw new Failure("Connection for " + name + + " at port " + port + + " wasn't accepted in " + timeout + "ms"); + } else { + logger.display("Listening was interrupted (caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e + ")"); + break; + } + } + } + } while (socket == null); + + } catch (IOException e) { + if (!shouldStop) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught IOException while listening for " + name + " connection at port " + port + ":\n\t" + e); + } else { + logger.display("Listening was interrupted (caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e + ")"); + } + } finally { + closeServerConnection(); + } + + if (!shouldStop) { + if (socket == null) { + throw new Failure("No " + name + " connection accepted at port " + port + " for " + timeout + "ms timeout"); + } + + onConnected(); + } + } + + /** + * Attach connection to the remote host and port. + * + * @param host + * name of remote host to attach to + * @param port + * port number to attach to + * + * @throws Failure + * if error occured while attaching + */ + public void attach(String host, int port) { + try { + logger.trace(TRACE_LEVEL_IO, "Attaching for " + name + " connection to host: " + host + ":" + port); + socket = new Socket(host, port); + socket.setTcpNoDelay(true); + logger.trace(TRACE_LEVEL_IO, "Attached for " + name + " connection to host: " + host + ":" + port); + } catch (IOException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught IOException while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + e); + } + if (!shouldStop) { + onConnected(); + } + } + + /** + * Continuously attach to the remote host for the specified timeout. + * + * @param host + * name of remote host to attach to + * @param port + * port number to attach to + * @param timeout + * attaching timeout in milliseconds + * + * @throws Failure + * if error occured while attaching + */ + public void continueAttach(String host, int port, long timeout) { + socket = null; + long timeToFinish = System.currentTimeMillis() + timeout; + ConnectException lastException = null; + logger.trace(TRACE_LEVEL_IO, "Attaching for " + name + " connection to host: " + host + ":" + port); + try { + for (long i = 0; !shouldStop && (timeout == 0 || System.currentTimeMillis() < timeToFinish); i++) { + try { + socket = new Socket(host, port); + logger.trace(TRACE_LEVEL_IO, "Attached for " + name + " connection to host: " + host + ":" + port); + break; + } catch (ConnectException e) { + logger.display("Attempt #" + i + " to attach for " + name + " connection failed:\n\t" + e); + lastException = e; + // check if listening process still alive + if (!checkConnectingProcess()) { + shouldStop = true; + throw new Failure("Break attaching to " + name + " connection: " + "listening process exited"); + } + // sleep between attempts + try { + Thread.sleep(DebugeeBinder.CONNECT_TRY_DELAY); + } catch (InterruptedException ie) { + throw new Failure("Thread interrupted while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + ie); + } + } + } + + } catch (IOException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught IOException while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + e); + } + + if (!shouldStop) { + if (socket == null) { + throw new Failure("Unable to attach for " + name + " connection to " + host + ":" + port + " for " + timeout + "ms timeout:\n\t" + + lastException); + } + + onConnected(); + } + } + + /** + * Set already bound serverSocket for further connection. + */ + public void setServerSocket(ServerSocket serverSocket) { + this.serverSocket = serverSocket; + } + + /** + * Set already connected socket for connection. + */ + public void setSocket(Socket socket) { + this.socket = socket; + if (!shouldStop) { + onConnected(); + } + } + + /** + * Get socket of already established connection. + */ + public Socket getSocket() { + return socket; + } + + /** + * Return true if another connecting process is still alive. + */ + public boolean checkConnectingProcess() { + if (connectingProcess == null) { + // no process to check + return true; + } + try { + int exitCode = connectingProcess.exitValue(); + } catch (IllegalThreadStateException e) { + // process is still alive + return true; + } + // process exited + return false; + } + + /** + * Set another connecting process to control if it is still alive. + */ + public void setConnectingProcess(Process process) { + connectingProcess = process; + } + + /** + * Check if connection is established. + */ + public boolean isConnected() { + return connected; + } + + /** + * Close socket and associated streams. + */ + public void close() { + if (!closed) { + shouldStop = true; + closeConnection(); + closed = true; + } + } + + /** + * Send the specified byte throw the connection. + */ + public void writeByte(byte b) throws IOException { + logger.trace(TRACE_LEVEL_IO, "Writing byte: " + b); + sout.write(b); + sout.flush(); + logger.trace(TRACE_LEVEL_IO, "Wrote byte: " + b); + } + + /** + * Read a byte and return it or -1. + */ + public int readByte() throws IOException { + logger.trace(TRACE_LEVEL_IO, "Reading byte"); + int b = sin.read(); + logger.trace(TRACE_LEVEL_IO, "Received byte: " + b); + return b; + } + + /** + * Perform some actions after connection established. + */ + protected void onConnected() { + if (!shouldStop) { + setSocketOptions(); + makeSocketStreams(); + connected = true; + } + } + + /** + * Set socket options after connection established. + */ + protected void setSocketOptions() { + } + + /** + * Close server socket. + */ + protected void closeServerConnection() { + if (serverSocket != null) { + try { + serverSocket.close(); + logger.trace(TRACE_LEVEL_IO, "ServerSocket closed: " + serverSocket); + } catch (IOException e) { + logger.display("# WARNING: " + "Caught IOException while closing ServerSocket of " + name + " connection:\n\t" + e); + } + } + } + + /** + * Close socket of connection to remote host. + */ + protected void closeHostConnection() { + if (socket != null) { + try { + socket.close(); + logger.trace(TRACE_LEVEL_IO, "Socket closed: " + socket); + } catch (IOException e) { + logger.display("# WARNING: " + "Caught IOException while closing socket of " + name + " connection:\n\t" + e); + } + } + } + + /** + * Close socket streams. + */ + protected void closeSocketStreams() { + if (sout != null) { + try { + logger.trace(TRACE_LEVEL_IO, "Closing socket output stream: " + sout); + sout.close(); + logger.trace(TRACE_LEVEL_IO, "Output stream closed: " + sout); + } catch (IOException e) { + logger.display("# WARNING: " + "Caught IOException while closing OutputStream of " + name + " connection:\n\t" + e); + } + } + if (sin != null) { + try { + logger.trace(TRACE_LEVEL_IO, "Closing socket input stream: " + sin); + sin.close(); + logger.trace(TRACE_LEVEL_IO, "Input stream closed: " + sin); + } catch (IOException e) { + logger.display("# WARNING: " + "Caught IOException while closing InputStream of" + name + " connection:\n\t" + e); + } + } + } + + /** + * Close sockets and associated streams. + */ + protected void closeConnection() { + if (connectionClosed) + return; + + logger.trace(TRACE_LEVEL_IO, "Closing " + name + " connection"); + closeSocketStreams(); + closeHostConnection(); + closeServerConnection(); + connectionClosed = true; + } + + /** + * Make up socket streams after connection established. + */ + protected void makeSocketStreams() { + try { + logger.trace(TRACE_LEVEL_IO, "Getting input/output socket streams for " + name + " connection"); + sout = socket.getOutputStream(); + logger.trace(TRACE_LEVEL_IO, "Got socket output stream: " + sout); + sin = socket.getInputStream(); + logger.trace(TRACE_LEVEL_IO, "Got socket input stream: " + sin); + } catch (IOException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught exception while making streams for " + name + " connection:\n\t" + e); + } + } + +} // BasicSocketConnection + +/** + * This class implements connection channel via TCP/IP sockets. After connection + * established special inner threads are started, which periodically test the + * connection by pinging each other. If ping timeout occurs connection is closed + * and any thread waiting for read from this connection gets exception. + * + * @see #setPingTimeout(long) + */ +public class SocketConnection extends BasicSocketConnection { + + private static final long PING_INTERVAL = 1 * 1000; // milliseconds + + private static byte DATA_BYTE = (byte) 0x03; + + private static byte DISCONNECT_BYTE = (byte) 0x04; + + private final Object inLock = new Object(); + private ObjectInputStream in = null; + + private final Object outLock = new Object(); + private ObjectOutputStream out = null; + + private volatile long pingTimeout = 0; // don't use ping + + /** + * Make an empty connection with specified name. + * + * @param log + * Log object for printing log messages + * @param name + * connection name + */ + public SocketConnection(Log log, String name) { + this(new Log.Logger(log, name + " connection> "), name); + } + + /** + * Make an empty connection with specified name. + * + * @param logger + * Logger object for printing log messages + * @param name + * connection name + */ + public SocketConnection(Log.Logger logger, String name) { + super(logger, name); + } + + /** + * Set ping timeout in milliseconds (0 means don't use ping at all). + */ + public void setPingTimeout(long timeout) { + logger.display("# WARNING: Setting ping timeout for " + name + " connection ingnored: " + timeout + " ms"); + pingTimeout = timeout; + } + + /** + * Returns value of current ping timeout in milliseconds (0 means ping is + * not used). + */ + public long getPingTimeout() { + return pingTimeout; + } + + /** + * Receive an object from remote host. + */ + public Object readObject() { + if (!isConnected()) { + throw new Failure("Unable to read object from not established " + name + " connection"); + } + + try { + return doReadObject(); + } catch (EOFException e) { + return null; + } catch (Exception e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught Exception while reading an object from " + name + " connection:\n\t" + e); + } + } + + /** + * Send an object to remote host. + */ + public void writeObject(Object object) { + if (!isConnected()) { + throw new Failure("Unable to send object throw not established " + name + " connection:\n\t" + object); + } + + try { + doWriteObject(object); + } catch (IOException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught IOException while writing an object to " + name + " connection:\n\t" + e); + } + } + + /** + * Close socket and associated streams and finish all internal threads. + */ + public void close() { + if (!closed) { + // disconnect(); + shouldStop = true; + super.close(); + closed = true; + } + } + + /** + * Perform some actions after connection has established. + */ + protected void onConnected() { + super.onConnected(); + } + + /** + * Do write an object to the connection channel. + */ + private void doWriteObject(Object object) throws IOException { + logger.trace(TRACE_LEVEL_IO, "writing object: " + object); + synchronized(outLock) { + out.writeObject(object); + out.flush(); + } + logger.trace(TRACE_LEVEL_PACKETS, "* sent: " + object); + } + + /** + * Do read an object from the connection channel. + */ + private Object doReadObject() throws IOException, ClassNotFoundException { + logger.trace(TRACE_LEVEL_IO, "Reading object"); + Object object = null; + synchronized(inLock) { + object = in.readObject(); + } + logger.trace(TRACE_LEVEL_PACKETS, "* recv: " + object); + return object; + } + + /** + * Close socket streams. + */ + protected void closeSocketStreams() { + synchronized(outLock) { + if (out != null) { + try { + logger.trace(TRACE_LEVEL_IO, "Closing socket output stream: " + out); + out.close(); + logger.trace(TRACE_LEVEL_IO, "Output stream closed: " + out); + } catch (IOException e) { + logger.display("# WARNING: " + "Caught IOException while closing ObjectOutputStream of " + name + " connection:\n\t" + e); + } + } + } + synchronized(inLock) { + if (in != null) { + try { + logger.trace(TRACE_LEVEL_IO, "Closing socket input stream: " + in); + in.close(); + logger.trace(TRACE_LEVEL_IO, "Input stream closed: " + in); + } catch (IOException e) { + logger.display("# WARNING: " + "Caught IOException while closing ObjectInputStream of" + name + " connection:\n\t" + e); + } + } + } + super.closeSocketStreams(); + } + + /** + * Close sockets and associated streams. + */ + protected void closeConnection() { + if (connectionClosed) + return; + connected = false; + shouldStop = true; + super.closeConnection(); + } + + /** + * Make up object streams for socket. + */ + protected void makeSocketStreams() { + try { + logger.trace(TRACE_LEVEL_IO, "Making input/output object streams for " + name + " connection"); + synchronized(outLock) { + out = new ObjectOutputStream(socket.getOutputStream()); + out.flush(); + } + logger.trace(TRACE_LEVEL_IO, "Output stream created: " + out); + synchronized(inLock) { + in = new ObjectInputStream(socket.getInputStream()); + } + logger.trace(TRACE_LEVEL_IO, "Input stream created: " + in); + } catch (IOException e) { + e.printStackTrace(logger.getOutStream()); + throw new Failure("Caught exception while making streams for " + name + " connection:\n\t" + e); + } + } + +} // SocketConnection diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java new file mode 100644 index 00000000000..95bad89141d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jpda; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import nsk.share.*; + +/* + * This class represents communication channel based on TCP/IP sockets. + * Usage of this class implies creation of objects of 2 types: server SocketIOPipe object + * (this object creates server socket and waits for incoming connection) and client + * SocketIOPipe (this object attaches to server). + * + * Server and client objects should be created using special static methods provided by this class, + * for example 'createServerIOPipe(Log log, int port, long timeout)' for server SocketIOPipe + * and 'createClientIOPipe(Log log, String host, int port, long timeout)' for client SocketIOPipe. + * + * When SocketIOPipe is created it can be used to send and receive strings using methods 'readln()' and 'println(String s)'. + * TCP/IP connection is established at the first attempt to read or write data. + * + * For example, if client process should send string 'OK' to the server process which is run + * at the host 'SERVER_HOST' following code can be written: + * + * Server side: + * + * // SocketIOPipe creates ServerSocket listening given port + * SocketIOPipe pipe = SocketIOPipe.createServerIOPipe(log, port, timeoutValue); + * + * // SocketIOPipe waits connection from client and reads data sent by the client + * String command = pipe.readln(); + * + * Client side: + * + * // initialize SocketIOPipe with given values of server host name and port + * SocketIOPipe pipe = SocketIOPipe.createClientIOPipe(log, 'SERVER_HOST', port, timeoutValue); + * + * String command = "OK"; + * // SocketIOPipe tries to create socket and send command to the server + * pipe.println(command); + * + */ +public class SocketIOPipe extends Log.Logger implements Finalizable { + + public static final int DEFAULT_TIMEOUT_VALUE = 1 * 60 * 1000; + + public static final String DEFAULT_PIPE_LOG_PREFIX = "SocketIOPipe> "; + + protected boolean listening; + + protected String host; + + protected int port; + + protected long timeout; + + protected SocketConnection connection; + + protected volatile boolean shouldStop; + + protected Process connectingProcess; + + protected ServerSocket serverSocket; + + protected String name; + + /** + * Make general IOPipe object with specified parameters. + */ + protected SocketIOPipe(String name, Log log, String logPrefix, String host, int port, long timeout, boolean listening) { + super(log, logPrefix); + this.host = host; + this.port = port; + this.timeout = timeout; + this.listening = listening; + this.name = name; + } + + /** + * Make general IOPipe object with specified parameters. + */ + protected SocketIOPipe(Log log, String logPrefix, String host, int port, long timeout, boolean listening) { + super(log, logPrefix); + this.host = host; + this.port = port; + this.timeout = timeout; + this.listening = listening; + } + + /** + * Create listening SocketIOPipe using given port + */ + public static SocketIOPipe createServerIOPipe(Log log, int port, long timeout) { + SocketIOPipe pipe = new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, null, 0, timeout, true); + + try { + ServerSocket ss = new ServerSocket(); + if (port == 0) { + // Only need SO_REUSEADDR if we're using a fixed port. If we + // start seeing EADDRINUSE due to collisions in free ports + // then we should retry the bind() a few times. + ss.setReuseAddress(false); + } + ss.bind(new InetSocketAddress(port)); + pipe.setServerSocket(ss); + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught IOException while binding for IOPipe connection: \n\t" + e); + } + + return pipe; + } + + /** + * Create listening SocketIOPipe using any free port + */ + public static SocketIOPipe createServerIOPipe(Log log, long timeout) { + return createServerIOPipe(log, 0, timeout); + } + + /** + * Create attaching SocketIOPipe using given port and timeout + */ + public static SocketIOPipe createClientIOPipe(Log log, String host, int port, long timeout) { + return new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, host, port, timeout, false); + } + + /** + * Return true if IOPipe connection established. + */ + public boolean isConnected() { + return (connection != null && connection.isConnected()); + } + + /** + * Returns port number used by SocketIOPipe + */ + public int getPort() { + return port; + } + + protected void setConnectingProcess(Process connectingProcess) { + this.connectingProcess = connectingProcess; + } + + protected void setServerSocket(ServerSocket serverSocket) { + this.serverSocket = serverSocket; + if (serverSocket != null) + port = serverSocket.getLocalPort(); + } + + /** + * Write (and flush) given line to this + * IOPipe cnannel. + * + * @throws Failure if error occured while sending data + */ + public void println(String line) { + if (connection == null) { + connect(); + } + connection.writeObject(line); + } + + /** + * Read a text line from this IOPipe channel, + * or return null if EOF reached. + * + * @throws Failure if error occured while reading data + */ + public String readln() { + if (connection == null) { + connect(); + } + String line = (String) connection.readObject(); + return line; + } + + /** + * Close this IOPipe connection. + */ + public void close() { + shouldStop = true; + if (connection != null) { + connection.close(); + } + } + + /** + * Establish IOPipe connection by attaching or accepting + * connection appropriately. + */ + protected void connect() { + if (connection != null) { + throw new TestBug("IOPipe connection is already established"); + } + + if (shouldStop) + return; + + connection = new SocketConnection(this, getName()); + + if (listening) { + connection.setConnectingProcess(connectingProcess); + if (serverSocket == null) { + connection.bind(port, timeout); + } else { + connection.setServerSocket(serverSocket); + } + + if (shouldStop) + return; + + // wait for connection from remote host + connection.accept(timeout); + + } else { + // attach from the debuggee's side + connection.continueAttach(host, port, timeout); + } + } + + /** + * Set ping timeout in milliseconds (0 means don't use ping at all). + */ + public void setPingTimeout(long timeout) { + if (connection == null) { + throw new TestBug("Attempt to set ping timeout for not established connection"); + } + connection.setPingTimeout(timeout); + } + + /** + * Returns value of current ping timeout in milliseconds (0 means ping is not used). + */ + public long getPingTimeout() { + if (connection == null) { + throw new TestBug("Attempt to get ping timeout for not established connection"); + } + return connection.getPingTimeout(); + } + + /** + * Perform finalization of the object by invoking close(). + */ + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + + /** + * Perform finalization of the object at exit by invoking finalize(). + */ + public void finalizeAtExit() throws Throwable { + finalize(); + } + + /** + * Field 'pipeCounter' and method 'getNextPipeNumber' are used to construct unique names for SocketIOPipes + */ + private static int pipeCounter; + + private synchronized int getNextPipeNumber() { + return pipeCounter++; + } + + /** + * Construct name for SocketIOPipe if it wasn't specified + */ + private String getName() { + if (name == null) { + name = "SocketIOPipe-" + getNextPipeNumber(); + } + + return name; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/StateTestThread.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/StateTestThread.java new file mode 100644 index 00000000000..dd868513627 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/StateTestThread.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.jpda; + +import nsk.share.TestBug; +import nsk.share.locks.MonitorLockingThread; + +/* + * StateTestThread sequentially switches its state in following order: + * - thread not started + * - thread is running + * - thread is sleeping + * - thread in Object.wait() + * - thread wait on java monitor + * - thread is finished + * + * To use this class create new instance of StateTestThread and sequentially call method nextState(). + */ +public class StateTestThread extends Thread { + // thread states available through ThreadReference.state() + public static String stateTestThreadStates[] = { "UNKNOWN", "RUNNING", "SLEEPING", "WAIT", "MONITOR", "ZOMBIE" }; + + private Object waitOnObject = new Object(); + + public StateTestThread(String name) { + super(name); + } + + private volatile boolean isRunning; + + private volatile boolean waitState; + + public int getCurrentState() { + return currentState; + } + + private MonitorLockingThread auxiliaryThread = new MonitorLockingThread(this); + + private boolean isExecutedWithErrors; + + private volatile boolean readyToBeBlocked; + + private String errorMessage; + + public void run() { + isRunning = true; + + // running state + while (isRunning) + ; + + try { + // sleeping state + sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + // expected exception + } + + synchronized (waitOnObject) { + try { + // wait state + while (waitState) + waitOnObject.wait(); + } catch (InterruptedException e) { + isExecutedWithErrors = true; + errorMessage = "StateTestThread was unexpected interrupted during waiting"; + } + } + + // start auxiliary thread which should acquire 'this' lock + auxiliaryThread.acquireLock(); + + readyToBeBlocked = true; + + // try acquire the same lock as auxiliaryThread, switch state to 'wait on monitor' + synchronized (this) { + + } + } + + private int currentState = 1; + + public void nextState() { + // check is thread states change as expected + if (isExecutedWithErrors) + throw new TestBug(errorMessage); + + switch (currentState++) { + case 1: + // start thread + start(); + + while (!isRunning) + yield(); + + break; + case 2: + // stop running + isRunning = false; + + while (this.getState() != Thread.State.TIMED_WAITING) + yield(); + + break; + case 3: + waitState = true; + + // stop sleeping + interrupt(); + + while (getState() != Thread.State.WAITING) + yield(); + + break; + case 4: + waitState = false; + + // stop wait + synchronized (waitOnObject) { + waitOnObject.notify(); + } + + while (!readyToBeBlocked || (getState() != Thread.State.BLOCKED)) + yield(); + + break; + case 5: + // let StateTestThread thread acquire lock + auxiliaryThread.releaseLock(); + try { + join(); + } catch (InterruptedException e) { + throw new TestBug("Unexpected exception: " + e); + } + break; + + default: + throw new TestBug("Invalid thread state"); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockLocker.java new file mode 100644 index 00000000000..942c2f415d3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockLocker.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import nsk.share.*; + +/* + * DeadlockLocker - class used for deadlock creation + * + * To create deadlock second 'inner' instance of DeadlockLocker is required. + * + * Deadlock creation scenario: + * - object acquires its resource + * - notify 'inner' through Wicket step1 that resource is locked and 'inner' can try to acquire this object's resource + * - wait notification through Wicket step2 from 'inner' that 'inner' acquired its resource + * - call readyWicket.unlock to notify thread waiting deadlock creation + * - try acquire locked inner's resource, at the same time inner trying to acquire locked this object's resource - deadlock is created + * + * Subclasses should implement method doLock() taking in account described scenario. + * + * Objects of DeadlockLocker should not be created directly, to create deadlocked threads use class DeadlockMaker + */ +abstract public class DeadlockLocker { + protected DeadlockLocker inner; + + protected Wicket step1; + + protected Wicket step2; + + // 'readyWicket' is used to notify DeadlockMacker that deadlock is almost created + protected Wicket readyWicket; + + public DeadlockLocker(Wicket step1, Wicket step2, Wicket readyWicket) { + this.step1 = step1; + this.step2 = step2; + this.readyWicket = readyWicket; + } + + public void setInner(DeadlockLocker inner) { + this.inner = inner; + } + + protected void checkInnerLocker() { + if (inner == null) { + throw new IllegalStateException(getClass().getName() + " deadlockLocker's inner locker is null"); + } + } + + protected abstract void doLock(); + + abstract public Object getLock(); + + private int lockCount; + + final public void lock() { + // call this method once + if (lockCount++ > 1) + return; + + // check that inner locker was set + checkInnerLocker(); + + doLock(); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockMaker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockMaker.java new file mode 100644 index 00000000000..9a89b2468ec --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockMaker.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import java.util.*; +import nsk.share.TestBug; +import nsk.share.Wicket; + +/* + * Class used to create deadlocked threads. It is possible create 2 or more deadlocked thread, also + * is is possible to specify resource of which type should lock each deadlocked thread + */ +public class DeadlockMaker { + // create deadlock with 2 threads + // lockType1 and lockType2 - type of locking resources used for deadlock creation + public static DeadlockedThread[] createDeadlockedThreads(LockType lockType1, LockType lockType2) { + DeadlockedThread[] resultThreads = new DeadlockedThread[2]; + + Wicket step1 = new Wicket(); + Wicket step2 = new Wicket(); + + Wicket readyWicket = new Wicket(2); + + DeadlockLocker locker1 = createLocker(lockType1, step1, step2, readyWicket); + DeadlockLocker locker2 = createLocker(lockType2, step2, step1, readyWicket); + locker1.setInner(locker2); + locker2.setInner(locker1); + + resultThreads[0] = new DeadlockedThread(locker1); + resultThreads[1] = new DeadlockedThread(locker2); + + resultThreads[0].start(); + resultThreads[1].start(); + + readyWicket.waitFor(); + + // additional check to be sure that all threads really blocked + waitForDeadlock(resultThreads); + + return resultThreads; + } + + // create deadlock with several threads + // locksTypes - type of locking resources used for deadlock creation + public static DeadlockedThread[] createDeadlockedThreads(List locksTypes) { + if (locksTypes.size() < 2) { + throw new IllegalArgumentException("Need at least 2 threads for deadlock"); + } + + int threadsNumber = locksTypes.size(); + + DeadlockedThread[] resultThreads = new DeadlockedThread[threadsNumber]; + + Wicket readyWicket = new Wicket(threadsNumber); + + DeadlockLocker deadlockLockers[] = new DeadlockLocker[threadsNumber]; + Wicket stepWickets[] = new Wicket[threadsNumber]; + + for (int i = 0; i < threadsNumber; i++) + stepWickets[i] = new Wicket(); + + int index1 = 0; + int index2 = 1; + for (int i = 0; i < threadsNumber; i++) { + Wicket step1 = stepWickets[index1]; + Wicket step2 = stepWickets[index2]; + + deadlockLockers[i] = createLocker(locksTypes.get(i), step1, step2, readyWicket); + + if (i > 0) + deadlockLockers[i - 1].setInner(deadlockLockers[i]); + + index1 = (index1 + 1) % threadsNumber; + index2 = (index2 + 1) % threadsNumber; + } + deadlockLockers[threadsNumber - 1].setInner(deadlockLockers[0]); + + for (int i = 0; i < threadsNumber; i++) { + resultThreads[i] = new DeadlockedThread(deadlockLockers[i]); + resultThreads[i].start(); + } + + readyWicket.waitFor(); + + // additional check to be sure that all threads really blocked + waitForDeadlock(resultThreads); + + return resultThreads; + } + + /* + * Wait when thread state will change to be sure that deadlock is really created + */ + static private void waitForDeadlock(DeadlockedThread[] threads) { + Set targetStates = new HashSet(); + + // thread is waiting for a monitor lock to enter a synchronized block/method + targetStates.add(Thread.State.BLOCKED); + + // thread calls LockSupport.park + targetStates.add(Thread.State.WAITING); + + // thread calls LockSupport.parkNanos or LockSupport.parkUntil + targetStates.add(Thread.State.TIMED_WAITING); + + for (Thread thread : threads) { + while (!targetStates.contains(thread.getState())) { + sleep(100); + } + } + } + + static private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + System.out.println("Unexpected exception: " + e); + e.printStackTrace(System.out); + + TestBug testBugException = new TestBug("Unexpected exception was throw: " + e); + testBugException.initCause(e); + throw testBugException; + } + } + + // create locker with given type + public static DeadlockLocker createLocker(LockType type, Wicket step1, Wicket step2, Wicket readyWicket) { + switch (type) { + case SYNCHRONIZED_METHOD: + return new SynchronizedMethodLocker(step1, step2, readyWicket); + case SYNCHRONIZED_BLOCK: + return new SynchronizedBlockLocker(step1, step2, readyWicket); + case REENTRANT_LOCK: + return new ReentrantLockLocker(step1, step2, readyWicket); + case JNI_LOCK: + return new JNIMonitorLocker(step1, step2, readyWicket); + } + + throw new IllegalArgumentException("Unsupported lock type: " + type); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockedThread.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockedThread.java new file mode 100644 index 00000000000..ff60ce16754 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockedThread.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import nsk.share.Wicket; + +/* + * Thread class used for deadlock creation, requires instance of DeadlockLocker to created deadlock. + * Objects of DeadlockedThread should not be created directly, to create deadlocked threads + * use class DeadlockMaker + */ +public class DeadlockedThread extends Thread { + private DeadlockLocker locker; + + private Wicket dedlockResolutionWicket = new Wicket(); + + // should call readyWicket.unlock() when deadlock is ready + public DeadlockedThread(DeadlockLocker locker) { + this.locker = locker; + } + + public void run() { + locker.lock(); + + // reach here if deadlock was resolved + dedlockResolutionWicket.unlockAll(); + + // sleep if deadlock was resolved + try { + sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + // ignore + } + } + + // If it is expected that deadlock with using of this DeadlockedThread should be resolved + // this method can be used for waiting this event + public void waitDeadlockResolution() { + // if deadlock was resolved DeadlockedThread calls dedlockResolutionWicket.unlockAll() + dedlockResolutionWicket.waitFor(); + } + + public DeadlockLocker getLocker() { + return locker; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.c b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.c new file mode 100644 index 00000000000..aad97b32636 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "jni.h" +#include "nsk_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_PTR + +#ifdef __cplusplus +#define JNI_ENV_ARG_2(x, y) y +#define JNI_ENV_ARG_3(x, y, z) y, z +#define JNI_ENV_ARG_4(x, y, z. a) y, z, a +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG_2(x,y) x, y +#define JNI_ENV_ARG_3(x, y, z) x, y, z +#define JNI_ENV_ARG_4(x, y, z, a) x, y, z, a +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + +JNIEXPORT void JNICALL +Java_nsk_share_locks_JNIMonitorLocker_doLock(JNIEnv *env, jobject thisObject) +{ +/* +This method executes JNI analog for following Java code: + + JNI_MonitorEnter(this); + + step1.unlockAll(); + step2.waitFor(); + readyWicket.unlock(); + inner.lock(); + + JNI_MonitorExit(this); +*/ + jint success; + jfieldID field; + jclass thisObjectClass; + + // fields 'step1' and 'step2' + jobject wicketObject; + + // class for fields 'step1', 'step2', 'readyWicket' + jclass wicketClass; + + // field 'inner' + jobject innerObject; + + // class for field 'inner' + jclass deadlockLockerClass; + + success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero")); + } + + thisObjectClass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, thisObject)); + + // step1.unlockAll() + field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "step1", "Lnsk/share/Wicket;")); + + wicketObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field)); + wicketClass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, wicketObject)); + + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, wicketObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, wicketClass, "unlockAll", "()V")))); + + // step2.waitFor() + field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "step2", "Lnsk/share/Wicket;")); + wicketObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field)); + + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, wicketObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, wicketClass, "waitFor", "()V")))); + + // readyWicket.unlock() + field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "readyWicket", "Lnsk/share/Wicket;")); + wicketObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field)); + + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, wicketObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, wicketClass, "unlock", "()V")))); + + // inner.lock() + field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "inner", "Lnsk/share/locks/DeadlockLocker;")); + innerObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field)); + deadlockLockerClass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, innerObject)); + + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, innerObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, deadlockLockerClass, "lock", "()V")))); + + success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero")); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.java new file mode 100644 index 00000000000..040c03e4187 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import nsk.share.Consts; +import nsk.share.Wicket; + +/* + * Class used for deadlock creation, acquires lock using JNI MonitorEnter + */ +public class JNIMonitorLocker extends DeadlockLocker { + static { + try { + System.loadLibrary("JNIMonitorLocker"); + } catch (UnsatisfiedLinkError e) { + System.out.println("Unexpected UnsatisfiedLinkError on loading library 'JNIMonitorLocker'"); + e.printStackTrace(System.out); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + + public JNIMonitorLocker(Wicket step1, Wicket step2, Wicket readyWicket) { + super(step1, step2, readyWicket); + } + + public Object getLock() { + return this; + } + + protected native void doLock(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockType.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockType.java new file mode 100644 index 00000000000..9a807a16814 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockType.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +/* + * Types of resources used for deadlock creation + */ +public enum LockType +{ + SYNCHRONIZED_METHOD, + SYNCHRONIZED_BLOCK, + REENTRANT_LOCK, + JNI_LOCK +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.c b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.c new file mode 100644 index 00000000000..be2acfb7785 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "jni.h" +#include "nsk_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_PTR + +#ifdef __cplusplus +#define JNI_ENV_ARG_2(x, y) y +#define JNI_ENV_ARG_3(x, y, z) y, z +#define JNI_ENV_ARG_4(x, y, z, a) y, z, a +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG_2(x,y) x, y +#define JNI_ENV_ARG_3(x, y, z) x, y, z +#define JNI_ENV_ARG_4(x, y, z, a) x, y, z, a +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + +JNIEXPORT void JNICALL +Java_nsk_share_locks_LockingThread_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject, jobject object) +{ + jint success; + jclass klass; + + success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, object)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero")); + } + + klass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, thisObject)); + + JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, thisObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, klass, "createStackFrame", "()V")))); + + success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, object)); + + if(success != 0) + { + NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success); + + JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero")); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.java new file mode 100644 index 00000000000..0ad364e4007 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.java @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; + +import nsk.share.Consts; +import nsk.share.Log; +import nsk.share.TestBug; +import nsk.share.TestJNIError; +import nsk.share.Wicket; + +/* + Thread with possibility acquiring monitors in different ways: + - entering synchronized method + - entering synchronized method for thread object itself + - entering synchronized static method + - entering synchronized method for thread class itself + - entering synchronized block on non-static object + - entering synchronized block on non-static on thread object itself + - entering synchronized block on static object + - entering synchronized block on static thread object itself + - JNI MonitorEnter. + + Description of required thread stack should be passed to LockingThread in constructor. + When started locking thread create required stack and sleep until not interrupted. + + LockingThread can relinquish acquired monitors in follows ways: + - relinquish single monitor through Object.wait - relinquishMonitor(int monitorIndex), + - relinquish single monitor through exiting from synchronized blocks/methods or through JNI MonitorExit - exitSingleFrame(), + - relinquish all monitors(exit from all synchronized blocks/methods) - stopLockingThread() + + Debug information about each acquired/relinquished monitor is stored and can be obtained through getMonitorsInfo(). + + To be sure that LockingThread have reached required state call method LockingThread.waitState(). + + Usage example: + + List stackFramesDescription = new ArrayList(); + stackFramesDescription.add(LockingThread.SYNCHRONIZED_METHOD); + stackFramesDescription.add(LockingThread.SYNCHRONIZED_OBJECT_BLOCK); + + LockingThread lockingThread = new LockingThread(log, stackFramesDescription); + + lockingThread.start(); + + // after calling waitState() LockingThread should complete stack creation + lockingThread.waitState(); + + lockingThread.exitSingleFrame(); + + // after calling waitState() LockingThread should complete exit from stack frame + lockingThread.waitState(); + */ +public class LockingThread extends Thread { + // native part uses TestJNIError class + private static final Class jniErrorKlass = TestJNIError.class; + static { + try { + System.loadLibrary("LockingThread"); + } catch (UnsatisfiedLinkError e) { + System.out.println("Unexpected UnsatisfiedLinkError on loading library 'LockingThread'"); + e.printStackTrace(System.out); + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED); + } + } + + /* + * Information about acquired monitor + */ + public static class DebugMonitorInfo { + public DebugMonitorInfo(Object monitor, int stackDepth, Thread thread, boolean isNative) { + this.monitor = monitor; + this.stackDepth = stackDepth; + this.thread = thread; + this.isNative = isNative; + } + + public Object monitor; + + public int stackDepth; + + public Thread thread; + + boolean isNative; + } + + // acquire JNI monitor through JNIMonitorEnter() + public static final String JNI_MONITOR_ENTER = "JNI_MONITOR_ENTER"; + + // entering synchronized static method + public static final String SYNCHRONIZED_STATIC_METHOD = "SYNCHRONIZED_STATIC_METHOD"; + + // entering synchronized static method for thread class itself + public static final String SYNCHRONIZED_STATIC_THREAD_METHOD = "SYNCHRONIZED_STATIC_THREAD_METHOD"; + + // entering synchronized method + public static final String SYNCHRONIZED_METHOD = "SYNCHRONIZED_METHOD"; + + // entering synchronized method for thread object itself + public static final String SYNCHRONIZED_THREAD_METHOD = "SYNCHRONIZED_THREAD_METHOD"; + + // entering synchronized block for thread object itself + public static final String SYNCHRONIZED_THIS_BLOCK = "SYNCHRONIZED_THIS_BLOCK"; + + // entering synchronized block + public static final String SYNCHRONIZED_OBJECT_BLOCK = "SYNCHRONIZED_OBJECT_BLOCK"; + + // entering synchronized block on static object + public static final String SYNCHRONIZED_BLOCK_STATIC_OBJECT = "SYNCHRONIZED_BLOCK_STATIC_OBJECT"; + + // entering synchronized block on static thread object itself + public static final String SYNCHRONIZED_BLOCK_STATIC_THREAD_OBJECT = "SYNCHRONIZED_BLOCK_STATIC_THREAD_OBJECT"; + + // entering frame without monitor acquiring + public static final String FRAME_WITHOUT_LOCK = "FRAME_WITHOUT_LOCK"; + + // all acquired monitors + private List monitorsInfo = new ArrayList(); + + // This parameter should be passed in constructor + // It describe how many locks and in which way LockingThread should acquire + private List stackFramesDescription; + + private Log log; + + // is during LockingThread's operations any errors occurred + private boolean executedWithErrors; + + public boolean isExecutedWithErrors() { + return executedWithErrors; + } + + public LockingThread(Log log, List stackFramesDescription) { + this.log = log; + this.stackFramesDescription = stackFramesDescription; + } + + // return array containing all acquired monitors + public DebugMonitorInfo[] getMonitorsInfo(boolean returnJNIMonitors) { + Map result = new HashMap(); + + for (int i = monitorsInfo.size() - 1; i >= 0; i--) { + DebugMonitorInfo monitorInfo = monitorsInfo.get(i); + + if ((returnJNIMonitors || !monitorInfo.isNative) && + + // don't return relinquished monitors + (monitorInfo.monitor != relinquishedMonitor) && + + // return only last monitor occurrence + !result.containsKey(monitorInfo.monitor)) { + result.put(monitorInfo.monitor, monitorInfo); + } + } + + return result.values().toArray(new DebugMonitorInfo[] {}); + } + + void log(String message) { + log.display(Thread.currentThread().getName() + ": " + message); + } + + // add debug information about acquired monitor + void addMonitorInfo(DebugMonitorInfo monitorInfo) { + monitorsInfo.add(monitorInfo); + } + + // remove debug information about acquired monitor (also should update information about stack depth) + void removeMonitorInfo(DebugMonitorInfo removedMonitor) { + for (DebugMonitorInfo monitor : monitorsInfo) { + if (monitor.stackDepth > removedMonitor.stackDepth) + monitor.stackDepth -= 2; + } + + monitorsInfo.remove(removedMonitor); + } + + // used for stack frames creation + private int currentIndex; + + // Recursive function used for stack frames creation + + // For example if LockingThread should acquire 1 monitor through synchronized block + // and 1 monitor through synchronized method pass list with values SYNCHRONIZED_METHOD and SYNCHRONIZED_OBJECT_BLOCK + // to the constructor and after running LockingThread will have following stack frames: + + // run() + // createStackFrame() + // ClassWithSynchronizedMethods().synchronizedMethod() // monitor for instance of ClassWithSynchronizedMethods is acquired here + // createStackFrame() + // synchronizedObjectBlock() // monitor for instance of Object is acquired here + // createStackFrame() + // doWait() + // sleep() + + // When LockingThread have created required stack frame it calls method doWait() and sleep(Long.MAX_VALUE) + + // If LockingThread should relinquish one of the acquired monitors it should be interrupted and after + // interrupting should call 'wait()' for specified monitor, and for this example LockingThread will have + // following stack frames: + + // run() + // createStackFrame() + // ClassWithSynchronizedMethods().synchronizedMethod() // monitor for instance of ClassWithSynchronizedMethods is acquired here + // createStackFrame() + // synchronizedObjectBlock() // monitor for instance of Object is acquired here + // createStackFrame() + // doWait() + // relinquishedMonitor.wait() + + // LockingThread still holds all other locks because of it didn't exit from corresponding synchronized methods and blocks. + // To let LockingThread acquire relinquished monitor 'relinquishedMonitor.notifyAll()' should be called, after this + // LockingThread will acquire this monitor again because of it still in corresponding synchronized method or block and + // it will have again such stack frames: + + // run() + // createStackFrame() + // ClassWithSynchronizedMethods().synchronizedMethod() // monitor for instance of ClassWithSynchronizedMethods is acquired here + // createStackFrame() + // synchronizedObjectBlock() // monitor for instance of Object is acquired here + // createStackFrame() + // doWait() + // sleep() + void createStackFrame() { + if (currentIndex < stackFramesDescription.size()) { + String frameDescription = stackFramesDescription.get(currentIndex); + + currentIndex++; + + if (frameDescription.equals(JNI_MONITOR_ENTER)) { + // for JNI monitors -1 is returned as stack depth + int currentStackDepth = -1; + Object object = new Object(); + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(object, currentStackDepth, this, true); + addMonitorInfo(monitorInfo); + log("Enter JNI monitor"); + nativeJNIMonitorEnter(object); + log("Exit JNI monitor"); + removeMonitorInfo(monitorInfo); + } else if (frameDescription.equals(SYNCHRONIZED_BLOCK_STATIC_OBJECT)) { + synchronizedBlockStaticObject(); + } else if (frameDescription.equals(SYNCHRONIZED_BLOCK_STATIC_THREAD_OBJECT)) { + synchronizedBlockStaticThreadObject(); + } else if (frameDescription.equals(SYNCHRONIZED_METHOD)) { + new ClassWithSynchronizedMethods().synchronizedMethod(this); + } else if (frameDescription.equals(SYNCHRONIZED_THREAD_METHOD)) { + synchronizedMethod(); + } else if (frameDescription.equals(SYNCHRONIZED_STATIC_METHOD)) { + ClassWithSynchronizedMethods.synchronizedStaticMethod(this); + } else if (frameDescription.equals(SYNCHRONIZED_STATIC_THREAD_METHOD)) { + synchronizedStaticMethod(this); + } else if (frameDescription.equals(SYNCHRONIZED_THIS_BLOCK)) { + synchronizedThisBlock(); + } else if (frameDescription.equals(SYNCHRONIZED_OBJECT_BLOCK)) { + synchronizedObjectBlock(); + } else if (frameDescription.equals(FRAME_WITHOUT_LOCK)) { + frameWithoutLock(); + } else + throw new TestBug("Invalid stack frame description: " + frameDescription); + } else { + // required stack is created + ready(); + doWait(); + } + + if (exitSingleFrame) { + if (currentIndex-- < stackFramesDescription.size()) { + // exit from single synchronized block/method + ready(); + doWait(); + } + } + } + + public Object getRelinquishedMonitor() { + return relinquishedMonitor; + } + + private Object relinquishedMonitor; + + private Wicket waitStateWicket = new Wicket(); + + private Thread.State requiredState; + + public void waitState() { + // try wait with timeout to avoid possible hanging (if LockingThread have finished execution because of uncaught exception) + int result = waitStateWicket.waitFor(60000); + + if (result != 0) { + throw new TestBug("Locking thread can't reach required state (waitStateWicket wasn't unlocked)"); + } + + if (requiredState == null) + throw new TestBug("Required state not specified"); + + long startTime = System.currentTimeMillis(); + + // additional check to be sure that LockingThread acquired state + while (this.getState() != requiredState) { + + // try wait with timeout to avoid possible hanging if something will go wrong + if ((System.currentTimeMillis() - startTime) > 60000) { + throw new TestBug("Locking thread can't reach required state (state: " + requiredState + " wasn't reached) in 1 minute"); + } + + yield(); + } + + requiredState = null; + + Object relinquishedMonitor = getRelinquishedMonitor(); + /* + * Changing thread state and release of lock is not single/atomic operation. + * As result there is a potential race when thread state (LockingThread) has + * been changed but the lock has not been released yet. To avoid this current + * thread is trying to acquire the same monitor, so current thread proceeds + * execution only when monitor has been really relinquished by LockingThread. + */ + if (relinquishedMonitor != null) { + synchronized (relinquishedMonitor) { + } + } + } + + // LockingThread acquired required state + private void ready() { + waitStateWicket.unlockAll(); + } + + // is LockingThread should relinquish single monitor + private volatile boolean relinquishMonitor; + + private int relinquishedMonitorIndex; + + // relinquish single monitor with given index through Object.wait() + public void relinquishMonitor(int index) { + if (index >= monitorsInfo.size()) { + throw new TestBug("Invalid monitor index: " + index); + } + + requiredState = Thread.State.WAITING; + waitStateWicket = new Wicket(); + relinquishMonitor = true; + relinquishedMonitorIndex = index; + + interrupt(); + + DebugMonitorInfo monitorInfo = monitorsInfo.get(relinquishedMonitorIndex); + + if (monitorInfo == null) + throw new TestBug("Invalid monitor index: " + relinquishedMonitorIndex); + } + + public void acquireRelinquishedMonitor() { + if (relinquishedMonitor == null) { + throw new TestBug("There is no relinquished monitor"); + } + + // Set requiredState to 'Thread.State.TIMED_WAITING' because of LockingThread call + // Thread.sleep(Long.MAX_VALUE) after monitor acquiring + requiredState = Thread.State.TIMED_WAITING; + + waitStateWicket = new Wicket(); + relinquishMonitor = false; + + synchronized (relinquishedMonitor) { + relinquishedMonitor.notifyAll(); + } + } + + public void stopLockingThread() { + requiredState = Thread.State.TIMED_WAITING; + + waitStateWicket = new Wicket(); + exitSingleFrame = false; + + interrupt(); + } + + // is thread should exit from single synchronized block/method + private boolean exitSingleFrame; + + public void exitSingleFrame() { + requiredState = Thread.State.TIMED_WAITING; + + waitStateWicket = new Wicket(); + exitSingleFrame = true; + + interrupt(); + } + + // LockingThread call this method when required state is reached + private void doWait() { + while (true) { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (InterruptedException e) { + // expected exception, LockingThread should be interrupted to change state + } + + // if single monitor should be relinquished through Object.wait() + if (relinquishMonitor) { + try { + DebugMonitorInfo monitorInfo = monitorsInfo.get(relinquishedMonitorIndex); + + if (monitorInfo == null) + throw new TestBug("Invalid monitor index: " + relinquishedMonitorIndex); + + relinquishedMonitor = monitorInfo.monitor; + + log("Relinquish monitor: " + relinquishedMonitor); + + // monitor is relinquished + ready(); + + // Really monitor is relinquished only when LockingThread calls relinquishedMonitor.wait(0) below, + // but to be sure that LockingThread have reached required state method waitState() should be called + // and this method waits when LockingThred change state to 'Thread.State.WAITING' + + while (relinquishMonitor) + relinquishedMonitor.wait(0); + + log("Acquire relinquished monitor: " + relinquishedMonitor); + } catch (Exception e) { + executedWithErrors = true; + log("Unexpected exception: " + e); + e.printStackTrace(log.getOutStream()); + } + + relinquishedMonitor = null; + + // monitor is acquired again + //(becuase we still are located in the frame where lock was acquired before we relinquished it) + ready(); + } else + // exit from frame + break; + } + } + + public void run() { + // LockingThread call Thread.sleep() when required stack frame was created + requiredState = Thread.State.TIMED_WAITING; + + createStackFrame(); + + // thread relinquished all monitors + ready(); + doWait(); + } + + static synchronized void synchronizedStaticMethod(LockingThread lockingThread) { + int currentStackDepth = lockingThread.expectedDepth(); + + lockingThread.log("Enter synchronized static thread method"); + + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(LockingThread.class, currentStackDepth, lockingThread, false); + lockingThread.addMonitorInfo(monitorInfo); + lockingThread.createStackFrame(); + lockingThread.removeMonitorInfo(monitorInfo); + + lockingThread.log("Exit synchronized static thread method"); + } + + // calculate stack depth at which monitor was acquired + int expectedDepth() { + // for each monitor call 2 methods: createStackFrame() and method which acquire monitor + // + when stack creation is finished call 3 methods: createStackFrame()->doWait()->sleep() + return (stackFramesDescription.size() - currentIndex) * 2 + 3; + } + + private native void nativeJNIMonitorEnter(Object object); + + synchronized void synchronizedMethod() { + int currentStackDepth = expectedDepth(); + + log("Enter synchronized thread method"); + + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(this, currentStackDepth, this, false); + addMonitorInfo(monitorInfo); + createStackFrame(); + removeMonitorInfo(monitorInfo); + + log("Exit synchronized thread method"); + } + + void synchronizedThisBlock() { + int currentStackDepth = expectedDepth(); + + log("Enter synchronized(this) block"); + + synchronized (this) { + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(this, currentStackDepth, this, false); + addMonitorInfo(monitorInfo); + createStackFrame(); + removeMonitorInfo(monitorInfo); + } + + log("Exit synchronized(this) block"); + } + + private static Object staticObject; + + // 'staticObjectInitializingLock' is used in synchronizedBlockStaticObject() and synchronizedBlockStaticThreadObject(). + // In this methods LockingThread initializes static object and enters in synchronized block + // for this static object, this actions are not thread safe(because of static fields are used) and 'staticObjectInitializingLock' + // is used to prevent races + private static ReentrantLock staticObjectInitializingLock = new ReentrantLock(); + + void synchronizedBlockStaticObject() { + int currentStackDepth = expectedDepth(); + + // initializing of 'staticObject' and entering to the synchronized(staticObject) block should be thread safe + staticObjectInitializingLock.lock(); + + staticObject = new Object(); + + log("Enter synchronized(static object) block"); + + synchronized (staticObject) { + // thread unsafe actions was done + staticObjectInitializingLock.unlock(); + + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(staticObject, currentStackDepth, this, false); + addMonitorInfo(monitorInfo); + createStackFrame(); + removeMonitorInfo(monitorInfo); + } + + log("Exit synchronized(static object) block"); + } + + private static LockingThread staticLockingThread; + + void synchronizedBlockStaticThreadObject() { + int currentStackDepth = expectedDepth(); + + // initializing of 'staticLockingThread' and entering to the synchronized(staticLockingThread) block should be thread safe + staticObjectInitializingLock.lock(); + + staticLockingThread = this; + + log("Enter synchronized(static thread object) block"); + + synchronized (staticLockingThread) { + // thread unsafe actions was done + staticObjectInitializingLock.unlock(); + + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(staticLockingThread, currentStackDepth, this, false); + addMonitorInfo(monitorInfo); + createStackFrame(); + removeMonitorInfo(monitorInfo); + } + + log("Exit synchronized(static thread object) block"); + } + + void synchronizedObjectBlock() { + int currentStackDepth = expectedDepth(); + + Object object = new Object(); + + log("Enter synchronized(object) block"); + + synchronized (object) { + DebugMonitorInfo monitorInfo = new DebugMonitorInfo(object, currentStackDepth, this, false); + addMonitorInfo(monitorInfo); + createStackFrame(); + removeMonitorInfo(monitorInfo); + } + + log("Exit synchronized(object) block"); + } + + private void frameWithoutLock() { + log("Enter frameWithoutLock"); + + createStackFrame(); + + for (DebugMonitorInfo monitor : monitorsInfo) + monitor.stackDepth -= 2; + + log("Exit frameWithoutLock"); + } +} + +//class containing synchronized method and synchronized static method, used by LockingThread +class ClassWithSynchronizedMethods { + public synchronized void synchronizedMethod(LockingThread lockingThread) { + int currentStackDepth = lockingThread.expectedDepth(); + + lockingThread.log("Enter synchronized method"); + + LockingThread.DebugMonitorInfo monitorInfo = new LockingThread.DebugMonitorInfo(this, currentStackDepth, lockingThread, false); + lockingThread.addMonitorInfo(monitorInfo); + lockingThread.createStackFrame(); + lockingThread.removeMonitorInfo(monitorInfo); + + lockingThread.log("Exit synchronized method"); + } + + public static synchronized void synchronizedStaticMethod(LockingThread lockingThread) { + int currentStackDepth = lockingThread.expectedDepth(); + + lockingThread.log("Enter synchronized static method"); + + LockingThread.DebugMonitorInfo monitorInfo = new LockingThread.DebugMonitorInfo(ClassWithSynchronizedMethods.class, currentStackDepth, + lockingThread, false); + lockingThread.addMonitorInfo(monitorInfo); + lockingThread.createStackFrame(); + lockingThread.removeMonitorInfo(monitorInfo); + + lockingThread.log("Exit synchronized static method"); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/MonitorLockingThread.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/MonitorLockingThread.java new file mode 100644 index 00000000000..4408dd2a553 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/MonitorLockingThread.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +/* + * Thread intended to hold given lock until method releaseLock() not called + * + * Example of usage: + * + * Object lockToHold = new Object(); + * MonitorLockingThread lockingThread = new MonitorLockingThread(lockToHold); + * + * // after calling this method lock 'lockToHold' is acquired by lockingThread + * lockingThread.acquireLock(); + * + * // after calling this method lockingThread releases 'lockToHold' and finishes execution + * lockingThread.releaseLock(); + */ +public class MonitorLockingThread extends Thread { + /* + * Class MonitorLockingThread is written for usage in tests provoking monitor contention. + * Typically in these tests exists thread holding lock (MonitorLockingThread) and another + * thread trying to acquire the same lock. But this scenario also requires one more thread + * which will force MonitorLockingThread to release lock when contention occurred, for this purpose + * auxiliary thread class LockFreeThread is written. + * + * Example of usage of MonitorLockingThread and LockFreeThread: + * + * Object lock = new Object(); + * MonitorLockingThread monitorLockingThread = new MonitorLockingThread(lock); + * + * MonitorLockingThread.LockFreeThread lockFreeThread = + * new MonitorLockingThread.LockFreeThread(Thread.currentThread(), monitorLockingThread); + * + * monitorLockingThread.acquireLock(); + * + * lockFreeThread.start(); + * + * // try to acquire lock which is already held by MonitorLockingThread (here monitor contention should occur), + * // when LockFreeThread finds that contention occurred it forces MonitorLockingThread to release lock + * // and current thread is able to continue execution + * synchronized (lock) { + * } + */ + public static class LockFreeThread extends Thread { + private Thread blockedThread; + + private MonitorLockingThread lockingThread; + + public LockFreeThread(Thread blockedThread, MonitorLockingThread lockingThread) { + this.blockedThread = blockedThread; + this.lockingThread = lockingThread; + } + + public void run() { + /* + * Wait when blockedThread's state will switch to 'BLOCKED' (at that moment monitor contention + * should already occur) and then force MonitorLockingThread to release lock + */ + while (blockedThread.getState() != Thread.State.BLOCKED) + yield(); + + lockingThread.releaseLock(); + } + } + + private volatile boolean isRunning = true; + + private volatile boolean holdsLock; + + private Object lockToHold; + + public MonitorLockingThread(Object lockToHold) { + this.lockToHold = lockToHold; + } + + public void run() { + synchronized (lockToHold) { + holdsLock = true; + while (isRunning) + yield(); + } + holdsLock = false; + } + + public void releaseLock() { + isRunning = false; + while (holdsLock) + yield(); + } + + public void acquireLock() { + start(); + while (!holdsLock) + yield(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/ReentrantLockLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/ReentrantLockLocker.java new file mode 100644 index 00000000000..d41c7eb8d21 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/ReentrantLockLocker.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import java.util.concurrent.locks.ReentrantLock; +import nsk.share.Wicket; + +/* + * Class used for deadlock creation, acquires java.util.concurrent.locks.ReentrantLock + */ +public class ReentrantLockLocker extends DeadlockLocker { + private ReentrantLock lock = new ReentrantLock(); + + public ReentrantLockLocker(Wicket step1, Wicket step2, Wicket readyWicket) { + super(step1, step2, readyWicket); + } + + public ReentrantLock getLock() { + return lock; + } + + protected void doLock() { + lock.lock(); + + try { + step1.unlockAll(); + step2.waitFor(); + readyWicket.unlock(); + inner.lock(); + } finally { + lock.unlock(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedBlockLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedBlockLocker.java new file mode 100644 index 00000000000..85ef4c56505 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedBlockLocker.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import nsk.share.Wicket; + +/* + * Class used for deadlock creation, acquires java lock + * using synchronized block + */ +public class SynchronizedBlockLocker extends DeadlockLocker { + private Object object = new Object(); + + public SynchronizedBlockLocker(Wicket step1, Wicket step2, Wicket readyWicket) { + super(step1, step2, readyWicket); + } + + public Object getLock() { + return object; + } + + protected void doLock() { + synchronized (object) { + step1.unlockAll(); + step2.waitFor(); + readyWicket.unlock(); + inner.lock(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedMethodLocker.java b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedMethodLocker.java new file mode 100644 index 00000000000..ad89ee30b85 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedMethodLocker.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.locks; + +import nsk.share.Wicket; + +/* + * Class used for deadlock creation, acquires java lock + * using synchronized method + */ +public class SynchronizedMethodLocker extends DeadlockLocker { + public SynchronizedMethodLocker(Wicket step1, Wicket step2, Wicket readyWicket) { + super(step1, step2, readyWicket); + } + + public Object getLock() { + return this; + } + + protected synchronized void doLock() { + step1.unlock(); + step2.waitFor(); + readyWicket.unlock(); + inner.lock(); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/log/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/log/Log.java new file mode 100644 index 00000000000..b2b19a3545b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/log/Log.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.log; + +/** + * Log interface. + */ +public interface Log { + /** + * Log at INFO level. + * + * @param o object to log + */ + public void info(Object o); + + /** + * Log at DEBUG level. + * + * @param o object to log + */ + public void debug(Object o); + + /** + * Log at WARN level. + * + * @param o object to log + */ + public void warn(Object o); + + /** + * Log at ERROR level + * + * @param o object to log + */ + public void error(Object o); + + /** + * Determine if logging at DEBUG level. + * + * @return true if debug logging is enabled, false otherwise + */ + public boolean isDebugEnabled(); + + /** + * Determine if logging at INFO level. + * + * @return true if info logging is enabled, false otherwise + */ + public boolean isInfoEnabled(); + + /** + * Determine if logging at WARN level. + * + * @return true if warn logging is enabled, false otherwise + */ + public boolean isWarnEnabled(); + + /** + * Determine if logging at ERROR level. + * + * @return true if error logging is enabled, false otherwise + */ + public boolean isErrorEnabled(); + + /** + * Enable/disable info output. + * + * @param infoEnabled + */ + public void setInfoEnabled(boolean infoEnabled); + + /** + * Enable/disable debug output. + * + * @param debugEnabled + */ + public void setDebugEnabled(boolean debugEnabled); + + /** + * Enable/disable warn output. + * @param warnEnabled + */ + public void setWarnEnabled(boolean warnEnabled); + + /** + * Enable/disable error output. + * @param errorEnabled + */ + public void setErrorEnabled(boolean errorEnabled); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogAware.java new file mode 100644 index 00000000000..8006be1c583 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogAware.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.log; + +/** + * Marker interface to inject Log. + * @see nsk.share.log.Log + */ +public interface LogAware { + /** + * Set log to use. + * + * @param log log + */ + public void setLog(Log log); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogSupport.java b/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogSupport.java new file mode 100644 index 00000000000..52a50016fc7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogSupport.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.log; + +import java.io.PrintStream; + +/** + * Basic Log that outputs to PrintStream. + * + * This log also tries to catch OutOfMemoryErrors and retry. + * + * @see nsk.share.log.Log + */ +public class LogSupport implements Log { + private final int attempts = 2; + private PrintStream out; + private boolean infoEnabled = true; + private boolean debugEnabled = true; + private boolean warnEnabled = true; + private boolean errorEnabled = true; + + public LogSupport() { + this(System.out); + } + + public LogSupport(PrintStream out) { + this.out = out; + } + + protected void logObject(Object o) { + if (o instanceof Throwable) { + logThrowable((Throwable) o); + return; + } + for (int i = 0; i < attempts; ++i) { + try { + out.println(o.toString()); + out.flush(); + break; + } catch (OutOfMemoryError e) { + System.gc(); + try { + Thread.sleep(500); + } catch (InterruptedException ie) { + } + } + } + out.flush(); + } + + protected void logThrowable(Throwable o) { + for (int i = 0; i < attempts; ++i) { + try { + o.printStackTrace(out); + out.flush(); + break; + } catch (OutOfMemoryError e) { + System.gc(); + try { + Thread.sleep(500); + } catch (InterruptedException ie) { + } + } + } + out.flush(); + } + + public void info(Object o) { + if (infoEnabled) + logObject(o); + } + + public void debug(Object o) { + if (debugEnabled) + logObject(o); + } + + public void warn(Object o) { + if (warnEnabled) + logObject(o); + } + + public void error(Object o) { + if (errorEnabled) + logObject(o); + } + + public boolean isInfoEnabled() { + return infoEnabled; + } + + public void setInfoEnabled(boolean infoEnabled) { + this.infoEnabled = infoEnabled; + } + + public boolean isDebugEnabled() { + return debugEnabled; + } + + public void setDebugEnabled(boolean debugEnabled) { + this.debugEnabled = debugEnabled; + } + + public boolean isWarnEnabled() { + return warnEnabled; + } + + public void setWarnEnabled(boolean warnEnabled) { + this.warnEnabled = warnEnabled; + } + + public boolean isErrorEnabled() { + return errorEnabled; + } + + public void setErrorEnabled(boolean errorEnabled) { + this.errorEnabled = errorEnabled; + } + + public void setOut(PrintStream out) { + this.out = out; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/README b/test/hotspot/jtreg/vmTestbase/nsk/share/native/README new file mode 100644 index 00000000000..d325d826518 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/README @@ -0,0 +1,186 @@ +Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This code is free software; you can redistribute it and\\\/or modify it +under the terms of the GNU General Public License version 2 only, as +published by the Free Software Foundation. +This code is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. + +--------------------------------------------------------------------------------- + +This directory contains source files of testbase_nsk native +framework, which provides support for native tests. + + Source files: + nsk_tools.h + nsk_tools.c + + Naming conventions: + macroses: NSK_* + functions: nsk_* + +Also this directory provides support for running native threads +in a platform independent manner. + + Source files: + native_thread.h + native_thread.c + + Naming conventions: + functions: THREAD_* + +The following source files declares a set of functions which +provides support for lists of various objects + + Source files: + nsk_list.h + nsk_list.c + + Naming conventions: + functions: nsk_list_* + +--------------------------------------------------------------------------------- + +nsk_tools.h + +Provides functions and macroses for the most usefull actions: + + - access native JVM environment in a compiler independent manner + + NSK_CPP_STUBn(function, env, arg1, ..., argn) + + - print error message with arguments + + NSK_COMPLAINn(format, arg1, ..., argn) + + - print verbose message with arguments + + NSK_DISPLAYn(format, arg1, ..., argn) + + - trace action execution + + NSK_TRACE(action) + + - trace action, check result for true/false and print error if required + + NSK_VERIFY(action) + NSK_VERIFY_NEGATIVE(action) + + - set verbose and trace mode of test output + + void nsk_setVerboseMode(int verbose); + int nsk_getVerboseMode(); + + void nsk_setTraceMode(int mode); + int nsk_getTraceMode(); + + - miscelaneous functions for printing messages + (hidden by above mentioned macroses) + +Typical example of using macroses NSK_CPP_STUB and NSK_VERIFY +for accesing JVM native environment: + + // jvm->GetEnv(jvm, &env, version) + if (!NSK_VERIFY( + NSK_CPP_STUB3(GetEnv, jvm, &env, JNI_VERSION_1_2) == JNI_OK)) { + return JNI_ERR; + } + +For more specific checks in invocations of JNI and JVMTI functions +use special macroses defined in share/jni and share/jvmti frameworks. + +--------------------------------------------------------------------------------- + +native_thread.h + +Provides platform-independent support for running native threads: + + - manage native threads + + void* THREAD_new(PROCEDURE procedure, void* context); + void* THREAD_start(void* thread); + void THREAD_waitFor(void* thread); + void THREAD_sleep(int seconds); + + - get status of native threads + + int THREAD_isStarted(void* thread); + int THREAD_hasFinished(void* thread); + int THREAD_status(void* thread); + +--------------------------------------------------------------------------------- + +nsk_list.h + +Provides support for lists of various objects: + + - managing list + const void* nsk_list_Create(); + int nsk_list_Destroy(const void *plist); + + - managing elements + const void* nsk_list_Add(const void *plist, const void *p); + int nsk_list_Delete(const void *plist, int ind); + + - getting element info + int nsk_list_getCount(const void *plist); + const void* nsk_list_Get(const void *plist, int ind); + +Typical example: + +int TOTAL_COUNT = 10; +typedef struct recordStruct { + int field1; + int field2; +} record; + +main() { + int i; + record *rec; + const void *plist; + + /* creating list */ + plist = nsk_list_create(); + + /* adding new elements */ + for (i = 0; i < TOTAL_COUNT; i ++) { + rec = (record *)malloc(sizeof(record)); + rec->field1 = i; + rec->field2 = i * 10; + if (!nsk_list_add(plist, rec)) { + free((void *)rec); + } + } + + /* getting elements */ + for (i = 0; i < TOTAL_COUNT; i ++) { + rec = (record *)nsk_list_get(plist, i); + printf("%3d %3d\n", rec->field1, rec->field2); + } + + /* deleteing elements */ + for (i = 0; i < TOTAL_COUNT; i ++) { + rec = (record *)nsk_list_get(plist, i); + free(rec); + nsk_list_remove(plist, 0); + } + + /* destroying list */ + nsk_list_destroy(plist); + +} + +--------------------------------------------------------------------------------- + diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.c b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.c new file mode 100644 index 00000000000..0c74b5ae385 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.c @@ -0,0 +1,211 @@ +/* +* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. +*/ + +#include +#include + +/* testbase_nsk threads: */ +#include + +/***************************************************************/ + +#ifdef _WIN32 + +#define windows +#include +#include /* for thread routines */ +typedef unsigned int THREAD_ID; + +#else // !_WIN32 + +#include + +#ifdef sun +#include +typedef thread_t THREAD_ID; +#else // !sun +#include +typedef pthread_t THREAD_ID; +#endif // !sun + +#endif // !_WIN32 + +/***************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A mirror to control a thread. + */ +typedef + struct STRUCT_THREAD { + PROCEDURE procedure; + void* context; + /**/ + int started; + int finished; + int status; + /**/ + THREAD_ID id; + } + THREAD; + +/***************************************************************/ + +/** + * Return a new thread mirror, or NULL if failed. + */ +void* THREAD_new(PROCEDURE procedure, void* context) { + THREAD* thread = (THREAD*)malloc(sizeof(THREAD)); + if (thread == NULL) + return NULL; + thread->procedure = procedure; + thread->context = context; + thread->started = 0; /* No */ + thread->finished = 0; + thread->status = -1; /* undefined */ + return thread; +} + +/***************************************************************/ + +#ifdef windows +unsigned __stdcall procedure(void* t) { +#else // !windows +void* procedure(void* t) { +#endif + THREAD* thread = (THREAD*)t; + thread->started = 1; + thread->status = thread->procedure(thread->context); + thread->finished = 1; + return 0; +} + +/** + * Return the thread if started OK, or NULL if failed. + */ +void* THREAD_start(void* t) { + THREAD* thread = (THREAD*)t; + if (thread == NULL) + return NULL; + if (thread->started != 0) + return NULL; +/* thread->started = 0; -- not yet */ + thread->finished = 0; + thread->status = 0; + { + +#ifdef windows + uintptr_t result = _beginthreadex(NULL,0,procedure,thread,0,&(thread->id)); + if (result == 0) { + perror("failed to create a native thread"); + return NULL; + } +#elif sun + int result = thr_create(NULL,0,procedure,thread,0,&(thread->id)); + if (result != 0) { + perror("failed to create a native thread"); + return NULL; + } +#else // !windows & !sun + int result = pthread_create(&(thread->id),NULL,procedure,thread); + if (result != 0) { + perror("failed to create a native thread"); + return NULL; + } +#endif // !windows & !sun + }; + return thread; +} + +/***************************************************************/ + +/** + * Return 1 if the thread has been started, or 0 if not, + * or -1 if thread==NULL. + */ +int THREAD_isStarted(void* t) { + THREAD* thread = (THREAD*)t; + if (thread == NULL) + return -1; + return (thread->started == 1); +} + +/** + * Return 1 if the thread has been started and already has finished, + * or 0 if the thread hasn't finish (or even hasn't been started), + * or -1 if thread==NULL. + */ +int THREAD_hasFinished(void* t) { + THREAD* thread = (THREAD*)t; + if (thread == NULL) + return -1; + return (thread->finished == 1); +} + +/** + * Return thread->status if thread has finished, + * or return 0 if thread hasn't finished, + * or retuen -1 if thread==NULL. + */ +int THREAD_status(void* t) { + THREAD* thread = (THREAD*)t; + if (thread == NULL) + return -1; + return thread->status; +} + +/***************************************************************/ + +/** + * Cycle with 1 second sleeps until the thread has finished; + * or return immediately, if thread==NULL. + */ +void THREAD_waitFor(void* t) { + THREAD* thread = (THREAD*)t; + if (thread == NULL) + return; + while (thread->finished == 0) + THREAD_sleep(1); /* yield for a second */ +} + +/***************************************************************/ + +/** + * Current thread sleeps. + */ +void THREAD_sleep(int seconds) { +#ifdef windows + Sleep(1000L * seconds); +#else + sleep(seconds); +#endif +} + +/***************************************************************/ + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.h b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.h new file mode 100644 index 00000000000..351a8dc8d44 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef NSK_SHARE_NATIVE_NATIVE_THREAD_H +#define NSK_SHARE_NATIVE_NATIVE_THREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A thread procedure with a void* argument and returning + * a status. + */ +typedef int(*PROCEDURE)(void*); + +/** + * Return a thread mirror, or NULL if failed. + */ +void* THREAD_new(PROCEDURE procedure, void* context); + +/** + * Return the thread if started OK, or NULL if failed. + */ +void* THREAD_start(void* thread); + +/** + * Return 1 if the thread has been started, or 0 if not, + * or -1 if thread==NULL. + */ +int THREAD_isStarted(void* thread); + +/** + * Return 1 if the thread has been started and already has finished, + * or 0 if the thread hasn't finish (or even hasn't been started), + * or -1 if thread==NULL. + */ +int THREAD_hasFinished(void* thread); + +/** + * Return thread->status if thread has finished, + * or return 0 if thread hasn't finished, + * or retuen -1 if thread==NULL. + */ +int THREAD_status(void* thread); + +/** + * Cycle with 1 second sleeps until the thread has finished; + * or return immediately, if thread==NULL. + */ +void THREAD_waitFor(void* thread); + +/** + * Current thread sleeps. + */ +void THREAD_sleep(int seconds); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.c b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.c new file mode 100644 index 00000000000..086901ba7e2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include + +#if (defined(WIN32) || defined (_WIN32) ) +#include +#define getpid _getpid +#define pidType int +#else +#include +#define pidType pid_t +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jlong +JNICALL Java_nsk_share_NativeUtils_getCurrentPID(JNIEnv * jni, jobject jobj) { + return (jlong) getpid(); +} +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.c b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.c new file mode 100644 index 00000000000..8452592c269 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include "nsk_list.h" +#include "nsk_tools.h" + +#define NSK_LIST_INIT_COUNT 20 + +typedef struct nsk_list_infoStruct { + const void **arr; + int elements_count; + int allocated_count; +} nsk_list_info; + + +static int nsk_list_size_void = sizeof(void *); + +/* ============================================================================= */ + +const void* nsk_list_create() { + + nsk_list_info *list_info; + + /* create nsk_list_info */ + list_info = (nsk_list_info *)malloc(sizeof(nsk_list_info)); + if (list_info == NULL) { + return NULL; + } + + list_info->allocated_count = NSK_LIST_INIT_COUNT; + list_info->elements_count = 0; + list_info->arr = (const void **)malloc(list_info->allocated_count * nsk_list_size_void); + if (list_info->arr == NULL) { + free(list_info); + return NULL; + } + + return list_info; +} + +/* ============================================================================= */ + +int nsk_list_destroy(const void *plist) { + + const nsk_list_info *list_info = (const nsk_list_info *)plist; + + free((void *)list_info->arr); + free((void *)plist); + + return NSK_TRUE; +} + +/* ============================================================================= */ + +int nsk_list_add(const void *plist, const void *p) { + + nsk_list_info *list_info = (nsk_list_info *)plist; + + if (list_info->elements_count >= list_info->allocated_count) { + list_info->allocated_count += NSK_LIST_INIT_COUNT; + list_info->arr = (const void **)realloc((void *)list_info->arr, list_info->allocated_count * nsk_list_size_void); + if (list_info->arr == NULL) { + return NSK_FALSE; + } + } + list_info->arr[list_info->elements_count++] = p; + + return NSK_TRUE; +} + +/* ============================================================================= */ + +int nsk_list_remove(const void *plist, int ind) { + + nsk_list_info *list_info = (nsk_list_info *)plist; + + if ((list_info->elements_count <= 0) + || ((ind < 0) || (ind >= list_info->elements_count))) + return NSK_FALSE; + + { + int i; + for (i = ind+1; i < list_info->elements_count; i++) { + list_info->arr[i - 1] = list_info->arr[i]; + } + } + list_info->arr[--list_info->elements_count] = 0; + + return NSK_TRUE; +} + +/* ============================================================================= */ + +int nsk_list_getCount(const void *plist) { + + return ((const nsk_list_info *)plist)->elements_count; +} + +/* ============================================================================= */ + +const void* nsk_list_get(const void *plist, int i) { + + const nsk_list_info *list_info = (const nsk_list_info *)plist; + + if ((i >= 0) && (i < list_info->elements_count)) { + return list_info->arr[i]; + } + + return NULL; +} + +/* ============================================================================= */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.h b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.h new file mode 100644 index 00000000000..2563e4288c8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef NSK_LIST +#define NSK_LIST + +/** + * Prepares array of pointers which has fixed INITIAL_SIZE. + * Memory for this array will be reallocated at the nsk_list_add() + * invocation if it is required. + * + * To release memory call nsk_list_destroy() + * + */ +const void* nsk_list_create(); + +/** + * Releases memory allocated for array of pointer + * Returns NSK_TRUE if array was successfully released + */ +int nsk_list_destroy(const void *plist); + +/** + * Returns number of elements + */ +int nsk_list_getCount(const void *plist); + +/** + * Returns pointer to i-th element. + * User must care for type cast of this pointer + */ +const void* nsk_list_get(const void *plist, int i); + +/** + * Adds new element into array. + * If array is full then memory is reallocated so as + * array could contain additional INITIAL_SIZE elements + * Returns NSK_TRUE if pointer was successfully added + */ +int nsk_list_add(const void *plist, const void *p); + +/** + * Removes i-th pointer from array + */ +int nsk_list_remove(const void *plist, int i); + +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.c b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.c new file mode 100644 index 00000000000..586e747b9d2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "nsk_mutex.h" + +#ifndef _WIN32 + +#include + +MUTEX* MUTEX_create() +{ + MUTEX* mutex = (MUTEX*)malloc(sizeof(pthread_mutex_t)); + if (mutex) + { + pthread_mutex_init((pthread_mutex_t*)mutex, NULL); + } + return mutex; +} + +void MUTEX_acquire(MUTEX* mutex) +{ + pthread_mutex_lock((pthread_mutex_t*)mutex); +} + +void MUTEX_release(MUTEX* mutex) +{ + pthread_mutex_unlock((pthread_mutex_t*)mutex); +} + +void MUTEX_destroy(MUTEX* mutex) +{ + pthread_mutex_destroy((pthread_mutex_t*)mutex); + + free(mutex); +} + +#else // _WIN32 + +#include + +MUTEX* MUTEX_create() +{ + MUTEX* mutex = (MUTEX*)malloc(sizeof(CRITICAL_SECTION)); + if (mutex) + { + InitializeCriticalSection((PCRITICAL_SECTION)mutex); + } + return mutex; +} + +void MUTEX_acquire(MUTEX* mutex) +{ + EnterCriticalSection((PCRITICAL_SECTION)mutex); +} + +void MUTEX_release(MUTEX* mutex) +{ + LeaveCriticalSection((PCRITICAL_SECTION)mutex); +} + +void MUTEX_destroy(MUTEX* mutex) +{ + DeleteCriticalSection((PCRITICAL_SECTION)mutex); + + free(mutex); +} + +#endif // _WIN32 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.h b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.h new file mode 100644 index 00000000000..65d8e67801d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef NSK_MUTEX_H +#define NSK_MUTEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Structure to hold mutex data (the content is platform-specific) + */ +typedef struct _MUTEX MUTEX; + +/** + * Create a mutex + */ +MUTEX* MUTEX_create(); + +/** + * Acquire a mutex + */ +void MUTEX_acquire(MUTEX* mutex); + +/** + * Release a mutex + */ +void MUTEX_release(MUTEX* mutex); + +/** + * Destroy a mutex + */ +void MUTEX_destroy(MUTEX* mutex); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.c b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.c new file mode 100644 index 00000000000..f5be8c7969d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include +#include + + +/*************************************************************/ + +#include "nsk_tools.h" + +/*************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************/ + +static struct { + int verbose; + int tracing; + int nComplains; +} nsk_context = {NSK_FALSE, NSK_TRACE_NONE, 0}; + +void nsk_setVerboseMode(int verbose) { + nsk_context.verbose = verbose; +} + +int nsk_getVerboseMode() { + return nsk_context.verbose; +} + +void nsk_setTraceMode(int mode) { + nsk_context.tracing = mode; +} + +int nsk_getTraceMode() { + return nsk_context.tracing; +} + +/*************************************************************/ + +static const char* file_basename(const char* fullname) { + const char* p; + const char* base = fullname;; + + if (fullname == NULL) + return NULL; + + for (p = fullname; *p != '\0'; p++) { + if (*p == '/' || *p == '\\') + base = p + 1; + } + return base; +} + +/*************************************************************/ + +void nsk_display(const char format[], ...) { + va_list ap; + va_start(ap,format); + nsk_lvdisplay(NULL,0,format,ap); + va_end(ap); +} + +void nsk_ldisplay(const char file[], int line, const char format[], ...) { + va_list ap; + va_start(ap,format); + nsk_lvdisplay(file,line,format,ap); + va_end(ap); +} + +void nsk_vdisplay(const char format[], va_list ap) { + nsk_lvdisplay(NULL,0,format,ap); +} + +void nsk_lvdisplay(const char file[], int line, const char format[], va_list ap) +{ + if (!nsk_context.verbose) + return; + if (file != NULL) + (void) nsk_printf("- %s, %d: ",file_basename(file),line); + (void) nsk_vprintf(format,ap); +} + +/*************************************************************/ + +void nsk_complain(const char format[], ...) { + va_list ap; + va_start(ap,format); + nsk_lvcomplain(NULL,0,format,ap); + va_end(ap); +} + +void nsk_lcomplain(const char file[], int line, const char format[], ...) +{ + va_list ap; + va_start(ap,format); + nsk_lvcomplain(file,line,format,ap); + va_end(ap); +} + +void nsk_vcomplain(const char format[], va_list ap) { + nsk_lvcomplain(NULL,0,format,ap); +} + +void nsk_lvcomplain(const char file[], int line, + const char format[], va_list ap) +{ + char msg_buf[1024]; + nsk_context.nComplains++; + if (!nsk_context.verbose) { + if ( nsk_context.nComplains > NSK_MAX_COMPLAINS_NON_VERBOSE ) { + return; + } + + if ( nsk_context.nComplains == NSK_MAX_COMPLAINS_NON_VERBOSE ) { + nsk_printf("# ...\n" + "# ERROR: too many complains, giving up to save disk space (CR 6341460)\n" + "# Please rerun the test with -verbose option to listen to the entire song\n"); + return; + } + } + + // Generate the message into a temp buffer since we can't call vfprintf on it twice, + // and also may need to modify a copy of the message slightly. + (void) vsnprintf(msg_buf, sizeof(msg_buf), format, ap); + + // Print a fake exception with the error for failure analysis. + // Do this only for the first complaint. + if (nsk_context.nComplains == 1) { + char msg_buf2[sizeof(msg_buf)]; + char* nl_ptr; + strncpy(msg_buf2, msg_buf, sizeof(msg_buf2)); + // Only include up to the 1st newline in the exception's error message. + nl_ptr = strchr(msg_buf2, '\n'); + if (nl_ptr != NULL) { + nl_ptr++; // Skip past the newline char. + *nl_ptr = '\0'; // Terminate the string after the newline char. + } else if (strlen(msg_buf2) != 0) { + msg_buf2[strlen(msg_buf2)-1] = '\n'; // Make sure we have a newline char at the end. + } + (void) nsk_printf("The following fake exception stacktrace is for failuire analysis. \n"); + (void) nsk_printf("nsk.share.Fake_Exception_for_RULE_Creation: "); + if (file != NULL) { + (void) nsk_printf("(%s:%d) ", file_basename(file), line); + } + (void) nsk_printf(msg_buf2); + (void) nsk_printf("\tat nsk_lvcomplain(%s:%d)\n", file_basename(__FILE__), __LINE__); + } + + if (file != NULL) { + (void) nsk_printf("# ERROR: %s, %d: ", file_basename(file), line); + } else { + (void) nsk_printf("# ERROR: "); + } + (void) nsk_printf(msg_buf); +} + +/*************************************************************/ + +void nsk_ltrace(int mode, const char file[], int line, const char format[], ...) { + va_list ap; + va_start(ap,format); + nsk_lvtrace(mode,file,line,format,ap); + va_end(ap); +} + +void nsk_lvtrace(int mode, const char file[], int line, const char format[], va_list ap) +{ + if ((nsk_context.tracing & mode) == 0) { + return; + } + + { + const char* prefix; + switch (mode) { + case NSK_TRACE_BEFORE: + prefix = ">>"; + break; + case NSK_TRACE_AFTER: + prefix = "<<"; + break; + default: + prefix = ".."; + break; + } + + (void) nsk_printf("- %s, %d: %s ",file_basename(file),line,prefix); + (void) nsk_vprintf(format,ap); + } +} + +/*************************************************************/ + +int nsk_lverify(int value, const char file[], int line, const char format[], ...) +{ + int fail=0; + va_list ap; + va_start(ap,format); + nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap); + if (!value) { + nsk_lvcomplain(file,line,format,ap); + nsk_printf("# verified assertion is FALSE\n"); + fail=1; + }; + va_end(ap); + return !fail; +} + +/*************************************************************/ + +int nsk_vprintf(const char format[], va_list ap) { + int x = vfprintf(stdout,format,ap); + int err = fflush(stdout); + if (err != 0) { + printf("stdout: fflush failed - err=%d errno=%d x=%d\n", err, errno, x); + fprintf(stderr, "stderr: fflush failed - err=%d errno=%d x=%d\n", err, errno, x); + } + assert(err == 0); + return x; +} + +int nsk_printf(const char format[], ...) { + int x; + va_list ap; + va_start(ap,format); + x = nsk_vprintf(format,ap); + va_end(ap); + return x; +} + +/*************************************************************/ + +#define MAX_HEX_COLUMNS 255 + +void nsk_printHexBytes(const char indent[], int columns, + size_t size, const unsigned char bytes[]) { + char hex[MAX_HEX_COLUMNS * 3 + 1]; + char ascii[MAX_HEX_COLUMNS + 1]; + char buf[16]; + + size_t i; + + if (size <= 0 || bytes == NULL) + return; + + for (i = 0; i < size; i += columns) { + int j; + + hex[0] = '\0'; + ascii[0] = '\0'; + + for (j = 0; j < columns && (i + j) < size; j++) { + unsigned int b = (unsigned int)bytes[i + j] & 0xFF; + char ch = (char)bytes[i + j]; + + if (!(isascii(ch) && isprint(ch))) ch = '.'; + sprintf(buf, " %02X", b); + strcat(hex, buf); + ascii[j] = ch; + } + + ascii[j] = '\0'; + if (j < columns) { + for (; j < columns; j++) { + strcat(hex, " "); + } + } + + nsk_printf("%s0x%08X: %s %s\n", indent, (int)i, hex, ascii); + } +} + +/*************************************************************/ + +const char* nsk_null_string(const char* str) { + return (str == NULL)? "" : str; +} + +/*************************************************************/ + +#ifdef __cplusplus +} +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.h b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.h new file mode 100644 index 00000000000..1001a887b58 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef NSK_TOOLS_DEFINED +#define NSK_TOOLS_DEFINED + +/*************************************************************/ + +#include + +/*************************************************************/ + +/** + * Use examples: + * + * jfieldID id = NSK_CPP_STUB3(jni,GetFieldID,clazz,name,sig); + * + * jvmtiError code = NSK_CPP_STUB0(jvmti,DisposeEnvironment); + * + */ + +#define NSK_CPP_STUB1(Func,env) (*env)->Func(env) +#define NSK_CPP_STUB2(Func,env,a) (*env)->Func(env,a) +#define NSK_CPP_STUB3(Func,env,a,b) (*env)->Func(env,a,b) +#define NSK_CPP_STUB4(Func,env,a,b,c) (*env)->Func(env,a,b,c) +#define NSK_CPP_STUB5(Func,env,a,b,c,d) (*env)->Func(env,a,b,c,d) +#define NSK_CPP_STUB6(Func,env,a,b,c,d,e) (*env)->Func(env,a,b,c,d,e) +#define NSK_CPP_STUB7(Func,env,a,b,c,d,e,f) (*env)->Func(env,a,b,c,d,e,f) +#define NSK_CPP_STUB8(Func,env,a,b,c,d,e,f,g) (*env)->Func(env,a,b,c,d,e,f,g) +#define NSK_CPP_STUB9(Func,env,a,b,c,d,e,f,g,h) (*env)->Func(env,a,b,c,d,e,f,g,h) + +#ifdef __cplusplus +#ifndef NSK_CPP_STUBS_ENFORCE_C +#undef NSK_CPP_STUB1 +#undef NSK_CPP_STUB2 +#undef NSK_CPP_STUB3 +#undef NSK_CPP_STUB4 +#undef NSK_CPP_STUB5 +#undef NSK_CPP_STUB6 +#undef NSK_CPP_STUB7 +#undef NSK_CPP_STUB8 +#undef NSK_CPP_STUB9 +#define NSK_CPP_STUB1(Func,env) env->Func() +#define NSK_CPP_STUB2(Func,env,a) env->Func(a) +#define NSK_CPP_STUB3(Func,env,a,b) env->Func(a,b) +#define NSK_CPP_STUB4(Func,env,a,b,c) env->Func(a,b,c) +#define NSK_CPP_STUB5(Func,env,a,b,c,d) env->Func(a,b,c,d) +#define NSK_CPP_STUB6(Func,env,a,b,c,d,e) env->Func(a,b,c,d,e) +#define NSK_CPP_STUB7(Func,env,a,b,c,d,e,f) env->Func(a,b,c,d,e,f) +#define NSK_CPP_STUB8(Func,env,a,b,c,d,e,f,g) env->Func(a,b,c,d,e,f,g) +#define NSK_CPP_STUB9(Func,env,a,b,c,d,e,f,g,h) env->Func(a,b,c,d,e,f,g,h) +#endif +#endif + +/*************************************************************/ + +/** + * Use examples: + * + * NSK_DISPLAY("Test started.\n"); + * NSK_COMPLAIN("Test FAILED: %s\n",reason); + * + * + */ + +#define NSK_DISPLAY0(format) nsk_ldisplay(__FILE__,__LINE__,format) +#define NSK_DISPLAY1(format,a) nsk_ldisplay(__FILE__,__LINE__,format,a) +#define NSK_DISPLAY2(format,a,b) nsk_ldisplay(__FILE__,__LINE__,format,a,b) +#define NSK_DISPLAY3(format,a,b,c) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c) +#define NSK_DISPLAY4(format,a,b,c,d) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d) +#define NSK_DISPLAY5(format,a,b,c,d,e) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e) +#define NSK_DISPLAY6(format,a,b,c,d,e,f) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f) +#define NSK_DISPLAY7(format,a,b,c,d,e,f,g) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f,g) +#define NSK_DISPLAY8(format,a,b,c,d,e,f,g,h) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h) +#define NSK_DISPLAY9(format,a,b,c,d,e,f,g,h,i) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h,i) + +#define NSK_COMPLAIN0(format) nsk_lcomplain(__FILE__,__LINE__,format) +#define NSK_COMPLAIN1(format,a) nsk_lcomplain(__FILE__,__LINE__,format,a) +#define NSK_COMPLAIN2(format,a,b) nsk_lcomplain(__FILE__,__LINE__,format,a,b) +#define NSK_COMPLAIN3(format,a,b,c) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c) +#define NSK_COMPLAIN4(format,a,b,c,d) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d) +#define NSK_COMPLAIN5(format,a,b,c,d,e) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e) +#define NSK_COMPLAIN6(format,a,b,c,d,e,f) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f) +#define NSK_COMPLAIN7(format,a,b,c,d,e,f,g) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f,g) +#define NSK_COMPLAIN8(format,a,b,c,d,e,f,g,h) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h) +#define NSK_COMPLAIN9(format,a,b,c,d,e,f,g,h,i) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h,i) + +#define NSK_VERIFY(action) (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \ + nsk_lverify(!!(action),__FILE__,__LINE__,"%s\n",#action)) +#define NSK_TRACE(action) {nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action); \ + (void)(action); \ + nsk_ltrace(NSK_TRACE_AFTER,__FILE__,__LINE__,"%s\n",#action);} +#define NSK_BEFORE_TRACE(action) nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action); \ + (void)(action) + +/*************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NSK_TRUE 1 +#define NSK_FALSE 0 + +#define NSK_TRACE_NONE 0 +#define NSK_TRACE_BEFORE 1 +#define NSK_TRACE_AFTER 2 +#define NSK_TRACE_ALL (NSK_TRACE_BEFORE | NSK_TRACE_AFTER) + +#define NSK_MAX_COMPLAINS_NON_VERBOSE 665 + +/** + * Mode is verbose iff "verbose" isn't NSK_FALSE. + */ +void nsk_setVerboseMode(int verbose); +int nsk_getVerboseMode(); + +/** + * Trace mode can be any combination of NSK_TRACE_* flags. + */ +void nsk_setTraceMode(int mode); +int nsk_getTraceMode(); + +/** + * Display the message if current mode is verbose. + */ +void nsk_display(const char format[], ...); +void nsk_vdisplay(const char format[], va_list args); +/** + * Add a prompt to point the file[] and line location. + */ +void nsk_ldisplay(const char file[], int line, const char format[], ...); +void nsk_lvdisplay(const char file[], int line, const char format[], va_list args); + +/** + * Complain the error message; add an "ERROR" prompt. + * No matter, is current mode verbose or not. + */ +void nsk_complain(const char format[], ...); +void nsk_vcomplain(const char format[], va_list args); +/** + * Add a prompt to point the file[] and line location. + */ +void nsk_lcomplain(const char file[], int line, const char format[], ...); +void nsk_lvcomplain(const char file[], int line, const char format[], va_list args); + +/** + * Trace executable actions, + */ +void nsk_ltrace(int mode, const char file[], int line, const char format[], ...); +void nsk_lvtrace(int mode, const char file[], int line, const char format[], va_list args); + +/** + * Complain the message as an error if value==0; return !!value. + * Add a prompt to point the file[] and line location. + * Display anyway if verbose. + */ +int nsk_lverify(int value, const char file[], int line, const char format[], ...); + +/** + * Same as printf() or vprintf(); but we may redefine this later. + */ +int nsk_vprintf(const char format[], va_list args); +int nsk_printf(const char format[], ...); + +/** + * Print given bytes array as hex numbers in multiple strings, each + * started with 'indent' prefix and offset info, followed by 'columns' bytes + * as hex numbers, then followed by the same bytes as ASCII chars where + * non-printable chars are replaced by '.', and terminated with new line char. + * Typically columns number is 16 and should not be greater than 255. + */ +void nsk_printHexBytes(const char indent[], int columns, + size_t size, const unsigned char bytes[]); + +/*************************************************************/ + +/** + * Returns str or "" if str is NULL; useful for printing strings. + */ +const char* nsk_null_string(const char* str); + +/*************************************************************/ + +#ifdef __cplusplus +} +#endif + +/*************************************************************/ + +#endif diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/FinRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/FinRunner.java new file mode 100644 index 00000000000..ec729e89584 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/FinRunner.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package nsk.share.runner; + +/** + * Helper that calls System.runFinalization(). + */ +public class FinRunner implements Runnable { + public void run() { + System.runFinalization(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/GCRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/GCRunner.java new file mode 100644 index 00000000000..4ebac377ae8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/GCRunner.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.runner; + +/** + * Helper that calls GC. + */ +public class GCRunner implements Runnable { + public void run() { + System.gc(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MemDiag.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MemDiag.java new file mode 100644 index 00000000000..f361c62b5ae --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MemDiag.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.runner; + +/** + * Helper that prints memory information. + */ +public class MemDiag implements Runnable { + private long sleepTime; + + public MemDiag() { + this(RunParams.getInstance().getSleepTime()); + } + + public MemDiag(long sleepTime) { + this.sleepTime = sleepTime; + } + + public void run() { + System.out.println(Runtime.getRuntime().freeMemory()); + // Ensure that interrupt status is not lost + if (Thread.currentThread().isInterrupted()) + return; + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunner.java new file mode 100644 index 00000000000..9b793356006 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunner.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.runner; + +import nsk.share.test.ExecutionController; + +/** + * Interface that defines a way to run several tasks. + * + * Several implementations are provided. + * + * @see nsk.share.runner.ThreadsRunner + */ +public interface MultiRunner extends Runnable { + /** + * Add a task. + * + * @param runnable task + */ + public void add(Runnable runnable); + + /** + * Remove a task. + * + * @param runnable task + */ + public void remove(Runnable runnable); + + /** + * Remove all tasks. + */ + public void removeAll(); + + /** + * Run tasks. + */ + public void run(); + + /** + * Get status of run. + * + * @return true if everything is alright, false if there are any errors + */ + public boolean isSuccessful(); + + /** + * Get execution controller for current thread. + * + * @returns execution controller for current thread + */ + public ExecutionController getExecutionController(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunnerAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunnerAware.java new file mode 100644 index 00000000000..07c20c3b873 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunnerAware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.runner; + +/** + * Marker interface for getting MultiRunner. + */ +public interface MultiRunnerAware { + public void setRunner(MultiRunner runner); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParams.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParams.java new file mode 100644 index 00000000000..ba596a288c6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParams.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.runner; + +import nsk.share.log.Log; +import nsk.share.test.StressOptions; +import java.io.PrintStream; + +public class RunParams { + private StressOptions stressOptions; + private long sleepTime = 500; + private long iterations = 0; + private int numberOfThreads; + private long seed = System.currentTimeMillis(); + private boolean runGCThread = false; + private boolean runFinThread = false; + private boolean runMemDiagThread = false; + private boolean runFinDiagThread = false; + private boolean runAllDiagThread = false; + private boolean runForever = false; + private long threadBlockSize = 64 * 1024 * 1024; + private boolean interruptThreads = false; + + public RunParams() { + this(new StressOptions()); + } + + public RunParams(StressOptions stressOptions) { + this.stressOptions = stressOptions; + numberOfThreads = getMediumLoadThreadsCount(); + } + + public RunParams(String[] args) { + this(); + parseCommandLine(args); + } + + /** + * Get an approximate memory which test should fill. + * + * This can be used to adjust the parameters of allocated objects + * to test run environment. Currently it is 3/5 of + * Runtime.getRuntime().maxMemory(). + */ + public long getTestMemory() { + return 3 * Runtime.getRuntime().maxMemory() / 5; + } + + /** + * Return memory to use for allocation of threads. + * + * This is currently 3/4 of getTestMemory(); + */ + public long getThreadsMemory() { + return 3 * getTestMemory() / 4; + } + + public final long getSleepTime() { + return sleepTime; + } + + public final void setSleepTime(long sleepTime) { + this.sleepTime = sleepTime; + } + + public final long getIterations() { + return iterations; + } + + public final void setIterations(long iterations) { + if (this.iterations != iterations) { + this.iterations = iterations; + System.out.println("Iterations: " + iterations); + } + } + + public int getBasicLoadThreadsCount() { + int cnt = (int) Math.min( + Integer.MAX_VALUE, + Math.min( + Runtime.getRuntime().availableProcessors(), + Math.round((double) Runtime.getRuntime().maxMemory() / threadBlockSize) + ) + ); + + // cnt could be equal to 0 in case maxMemory is less than threadBlockSize then + // so, need to check this + return (cnt > 0 ? cnt : 1); + } + + public int getMediumLoadThreadsCount() { + return 2 * getBasicLoadThreadsCount(); + } + + public int getHighLoadThreadsCount() { + return 100 * getBasicLoadThreadsCount(); + } + + public final int getNumberOfThreads() { + return numberOfThreads * stressOptions.getThreadsFactor(); + } + + public final void setNumberOfThreads(int numberOfThreads) { + this.numberOfThreads = numberOfThreads; + } + + public final long getSeed() { + return seed; + } + + public final void setSeed(long seed) { + this.seed = seed; + } + + public final boolean isRunGCThread() { + return runGCThread; + } + + public final void setRunGCThread(boolean runGCThread) { + this.runGCThread = runGCThread; + } + + public final boolean isRunFinThread() { + return runFinThread; + } + + public final void setRunFinThread(boolean runFinThread) { + this.runFinThread = runFinThread; + } + + public final boolean isRunMemDiagThread() { + return runMemDiagThread; + } + + public final void setRunMemDiagThread(boolean runMemDiagThread) { + this.runMemDiagThread = runMemDiagThread; + } + + public final boolean isRunFinDiagThread() { + return runFinDiagThread; + } + + public final void setRunFinDiagThread(boolean runFinDiagThread) { + this.runFinDiagThread = runFinDiagThread; + } + + public final boolean isRunAllDiagThread() { + return runAllDiagThread; + } + + public final void setRunAllDiagThread(boolean runAllDiagThread) { + this.runAllDiagThread = runAllDiagThread; + } + + public final boolean isRunForever() { + return runForever; + } + + public final void setRunForever(boolean runForever) { + this.runForever = runForever; + } + + public final boolean isInterruptThreads() { + return interruptThreads; + } + + public final void setInterruptThreads(boolean interruptThreads) { + this.interruptThreads = interruptThreads; + } + + public final StressOptions getStressOptions() { + return stressOptions; + } + + public void parseCommandLine(String[] args) { + if (args == null) + return; + stressOptions.parseCommandLine(args); + for (int i = 0; i < args.length; ++i) { + if (args[i].equals("-f")) + runForever = true; + else if (args[i].equals("-tg")) + runGCThread = true; + else if (args[i].equals("-tf")) + runFinThread = true; + else if (args[i].equals("-Dm")) + runMemDiagThread = true; + else if (args[i].equals("-Dm-")) + runMemDiagThread = false; + else if (args[i].equals("-Df1")) + runFinDiagThread = true; + else if (args[i].equals("-Df")) + runFinDiagThread = true; + else if (args[i].equals("-s")) + seed = Long.parseLong(args[++i]); + else if (args[i].equals("-t")) + numberOfThreads = Integer.parseInt(args[++i]); + else if (args[i].equals("-it")) + interruptThreads = true; + else if (args[i].equals("-iterations")) + iterations = Integer.parseInt(args[++i]); + } + printConfig(System.out); + } + + public void prinUsage() { + } + + public void printConfig(PrintStream out) { + stressOptions.printInfo(out); + out.println("Max memory: " + Runtime.getRuntime().maxMemory()); + out.println("Sleep time: " + sleepTime); + out.println("Iterations: " + iterations); + out.println("Number of threads: " + numberOfThreads); + out.println("Seed: " + seed); + out.println("Run GC thread: " + runGCThread); + out.println("Run mem diag thread: " + runMemDiagThread); + out.println("Run forever: " + runForever); + } + + public void logConfig(Log log) { + log.debug("Max memory: " + Runtime.getRuntime().maxMemory()); + log.debug("Sleep time: " + sleepTime); + log.debug("Iterations: " + iterations); + log.debug("Number of threads: " + numberOfThreads); + log.debug("Seed: " + seed); + log.debug("Run GC thread: " + runGCThread); + log.debug("Run mem diag thread: " + runMemDiagThread); + log.debug("Run forever: " + runForever); + } + + private static RunParams instance; + + public static RunParams getInstance() { + synchronized (RunParams.class) { + if (instance == null) + instance = new RunParams(); + return instance; + } + } + + public static void setInstance(RunParams runParams) { + synchronized (RunParams.class) { + instance = runParams; + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParamsAware.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParamsAware.java new file mode 100644 index 00000000000..af30af948d0 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParamsAware.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.runner; + +/** + * Marker interface to signify that run params are needed. + */ +public interface RunParamsAware { + public void setRunParams(RunParams runParams); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java new file mode 100644 index 00000000000..d37aa351fe0 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.runner; + +import nsk.share.Wicket; +import nsk.share.gc.OOMStress; +import nsk.share.log.*; +import nsk.share.test.Stresser; +import nsk.share.test.ExecutionController; +import nsk.share.TestBug; +import java.util.List; +import java.util.ArrayList; + +/** + * Helper to assist in running threads. + * + * This class starts a number of threads which run some tasks in cycle. + * They exit after some time or after some iterations as + * determined by RunParams. + */ +public class ThreadsRunner implements MultiRunner, LogAware, RunParamsAware { + + private Log log; + private RunParams runParams; + private List runnables = new ArrayList(); + private List threads = new ArrayList(); + private Wicket wicket = new Wicket(); + private Wicket finished; + private boolean started = false; + private boolean successful = true; + + public ThreadsRunner() { + this(RunParams.getInstance()); + } + + public ThreadsRunner(RunParams runParams) { + setRunParams(runParams); + } + + public final void setLog(Log log) { + this.log = log; + } + + private class ManagedThread extends Thread { + + private Stresser stresser; + private Throwable exception; + private Runnable test; + private boolean shouldWait; + + public ManagedThread(Runnable test) { + super(test.toString()); + this.test = test; + this.shouldWait = true; + this.stresser = new Stresser(this.getName(), runParams.getStressOptions()); + } + + public void run() { + wicket.waitFor(); + try { + stresser.start(runParams.getIterations()); + while (!this.isInterrupted() && stresser.iteration()) { + test.run(); + yield(); + } + waitForOtherThreads(); + } catch (OutOfMemoryError oom) { + waitForOtherThreads(); + if (test instanceof OOMStress) { + // Test stressing OOM, not a failure. + log.info("Caught OutOfMemoryError in OOM stress test, omitting exception."); + } else { + failWithException(oom); + } + } catch (Throwable t) { + waitForOtherThreads(); + failWithException(t); + } finally { + stresser.finish(); + } + } + + private void waitForOtherThreads() { + if (shouldWait) { + shouldWait = false; + finished.unlock(); + finished.waitFor(); + } else { + throw new TestBug("Waiting a second time is not premitted"); + } + } + + private void failWithException(Throwable t) { + log.debug("Exception in "); + log.debug(test); + log.debug(t); + exception = t; + } + + public void forceFinish() { + stresser.forceFinish(); + if (runParams.isInterruptThreads()) { + log.debug("Interrupting: " + this); + this.interrupt(); + } + } + + public final Throwable getException() { + return exception; + } + + public final ExecutionController getExecutionController() { + return stresser; + } + } + + public void add(Runnable runnable) { + runnables.add(runnable); + } + + public void remove(Runnable runnable) { + runnables.remove(runnable); + } + + public void removeAll() { + runnables.clear(); + } + + private Runnable get(int index) { + return (Runnable) runnables.get(index); + } + + public Thread getThread(int index) { + return threads.get(index); + } + + private int getCount() { + return runnables.size(); + } + + private void prepare() { + } + + private void create() { + int threadCount = runnables.size(); + finished = new Wicket(threadCount); + for (int i = 0; i < threadCount; ++i) { + threads.add(new ManagedThread(get(i))); + } + } + + /** + * Start threads that run the tasks. + */ + public void start() { + if (started) { + return; + } + create(); + prepare(); + for (int i = 0; i < threads.size(); ++i) { + Thread t = (Thread) threads.get(i); + log.debug("Starting " + t); + t.start(); + } + wicket.unlock(); + started = true; + } + + /** + * Stop threads that run the tasks. + */ + public void forceFinish() { + log.info("Forcing threads to finish"); + for (int i = 0; i < threads.size(); i++) { + ManagedThread thread = threads.get(i); + thread.forceFinish(); + } + } + + /** + * Join threads that run the tasks. + */ + public void join() throws InterruptedException { + for (int i = 0; i < threads.size(); ++i) { + Thread t = (Thread) threads.get(i); + //log.debug("Joining " + t); + t.join(); + } + } + + private int dumpFailures() { + int n = 0; + for (int i = 0; i < threads.size(); i++) { + ManagedThread thread = threads.get(i); + Throwable exception = thread.getException(); + if (exception != null) { + if (n == 0) { + log.error("Failures summary:"); + } + ++n; + log.error(exception); + } + } + if (n == 0) { + log.info("No unexpected exceptions/errors are thrown"); + } + return n; + } + + private ManagedThread findManagedThread(Thread t) { + for (int i = 0; i < threads.size(); i++) { + ManagedThread mt = threads.get(i); + if (mt == t) { + return mt; + } + } + return null; + } + + /** + * Run threads as determined by RunParams. + * + * Start threads, run for some time or for some number of iterations, + * then join and report if there were any exceptions. + * + * This method may additionally run other threads (as determined by RunParams): + * - thread that does System.gc() in cycle, @see GCRunner + * - thread that prints memory information in cycle, @see MemDiag + * - thread that prints information about FinMemoryObject's in cycle, @see FinDiag + * - thread that prints information about AllMemoryObject's in cycle, @see AllDiag + * + * @return true if there were no exceptions, false otherwise + */ + public void run() { + if (runParams.isRunGCThread()) { + add(new GCRunner()); + } + if (runParams.isRunFinThread()) { + add(new FinRunner()); + } + if (runParams.isRunMemDiagThread()) { + add(new MemDiag()); + } + try { + start(); + join(); + successful = dumpFailures() == 0; + } catch (Throwable t) { + log.info("Unexpected exception during the run."); + log.info(t); + successful = false; + } + } + + public boolean isSuccessful() { + return successful; + } + + public ExecutionController getExecutionController() { + Thread ct = Thread.currentThread(); + ManagedThread t = findManagedThread(ct); + if (t != null) { + return t.getExecutionController(); + } else { + throw new TestBug("Unable to find managed thread for thread (this method should be called from one of managed threads): " + ct); + } + } + + public void runForever() { + start(); + } + + public final void setRunParams(RunParams runParams) { + this.runParams = runParams; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersBTree.java b/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersBTree.java new file mode 100644 index 00000000000..319d240f248 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersBTree.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.sysdict; + +import nsk.share.*; + +/** + * A binary tree of class loaders. + * + * @see TreeNodesDenotation + */ +public class ClassLoadersBTree { + /** + * Cannot instantiate while a tree root and height + * are not specified. + * + * @see #ClassLoadersBTree(ClassLoader,int) + */ + protected ClassLoadersBTree() { + } + + /** + * Given the root loader, instantiate a binary tree + * of loaders up to the given tree height. + * + * @see #getHeight() + * @see #getRoot() + * @see #getLoader(String) + * @see #getLoader(int,int) + */ + public ClassLoadersBTree(ClassLoader root, int height) { + if (height < 1) + throw new IllegalArgumentException("wrong height: " + height); + loaders = new ClassLoader [ height ] []; + for (int level=0; levellevel of + * this loaders tree, and having the given item + * number at the enumeration of that level. + * + *

      The value of level must be from 0 + * to getHeight()-1, and the item number + * must be from 0 to 2level-1. + * + * @see #getHeight() + * @see #getRoot() + * @see #getLoader(String) + */ + public ClassLoader getLoader(int level, int item) { + return loaders[level][item]; + } + + /** + * Return the loader having the giving name at + * the standard denotation of binary tree nodes. + * + * @see #getHeight() + * @see #getRoot() + * @see #getLoader(int,int) + */ + public ClassLoader getLoader(String name) { + int[] index = denotation.indexFor(name); + int level = index[0]; + int item = index[1]; + return loaders[level][item]; + } + + /** + * Return the tree's height. + * + * @see #ClassLoadersBTree(ClassLoader,int) + * @see #getLoader(int,int) + * @see #getLoader(String) + */ + public int getHeight() { + return loaders.length; + } + + /** + * Return the tree's root loader. + * + * @see #ClassLoadersBTree(ClassLoader,int) + * @see #getLoader(int,int) + * @see #getLoader(String) + */ + public ClassLoader getRoot() { + return loaders[0][0]; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersChain.java b/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersChain.java new file mode 100644 index 00000000000..741ef6ac837 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersChain.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.sysdict; + +import nsk.share.*; + +/** + * A chain of class loaders. Imagine a chain as a tower + * growing downstairs: the 0th level is the + * root, and a level n+1 loader has the nth + * loader as the parent. + */ +public class ClassLoadersChain { + /** + * Cannot instantiate while a chain root and height + * are not specified. + * + * @see #ClassLoadersChain(ClassLoader,int) + */ + protected ClassLoadersChain() { + } + + /** + * Given the root loader, instantiate a chain + * of loaders up to the given height. + * + * @see #getHeight() + * @see #getRoot() + * @see #getLoader(int) + */ + public ClassLoadersChain(ClassLoader root, int height) { + if (height < 1) + throw new IllegalArgumentException("wrong height: " + height); + loaders = new ClassLoader [ height ]; + loaders[0] = root; + for (int i=1; ilevel. + * The value of level must be from 0 + * to getHeight()-1. + * + * @see #getHeight() + * @see #getRoot() + */ + public ClassLoader getLoader(int level) { + return loaders[level]; + } + + /** + * Return the chain's height. + * + * @see #ClassLoadersChain(ClassLoader,int) + * @see #getLoader(int) + */ + public int getHeight() { + return loaders.length; + } + + /** + * Return the chain's root loader. + * + * @see #ClassLoadersChain(ClassLoader,int) + * @see #getLoader(int) + */ + public ClassLoader getRoot() { + return loaders[0]; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Dumpable.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Dumpable.java new file mode 100644 index 00000000000..05900a87548 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Dumpable.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +import nsk.share.log.Log; + +public interface Dumpable { + public void dump(Log log); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/ExecutionController.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/ExecutionController.java new file mode 100644 index 00000000000..1b71c38ec46 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/ExecutionController.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +public interface ExecutionController { + public void start(long stdIterations); + public boolean iteration(); + public boolean continueExecution(); + public long getIteration(); + public void finish(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Initializable.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Initializable.java new file mode 100644 index 00000000000..621a219781b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Initializable.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +/** + * Marker interface for initialization. + */ +public interface Initializable { + public void initialize(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyFormatString.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyFormatString.java new file mode 100644 index 00000000000..472ae020c40 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyFormatString.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +public class LazyFormatString { + + private String format; + private Object[] args; + + public LazyFormatString(String format, Object... args) { + this.format = format; + this.args = args; + } + + @Override + public String toString() { + return String.format(format, args); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyIntArrayToString.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyIntArrayToString.java new file mode 100644 index 00000000000..4fb2ce33dfd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyIntArrayToString.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +import java.util.Arrays; + +public class LazyIntArrayToString { + + private int[] array; + + public LazyIntArrayToString(int[] array) { + this.array = array; + } + + @Override + public String toString() { + return Arrays.toString(array); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyObjectArrayToString.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyObjectArrayToString.java new file mode 100644 index 00000000000..cdfa4993631 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyObjectArrayToString.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +import java.util.Arrays; + +public class LazyObjectArrayToString { + + private Object[] array; + + public LazyObjectArrayToString(Object[] array) { + this.array = array; + } + + @Override + public String toString() { + return Arrays.toString(array); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/LocalRandom.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LocalRandom.java new file mode 100644 index 00000000000..f261c947a36 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LocalRandom.java @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +import java.util.concurrent.ThreadLocalRandom; +import nsk.share.TestFailure; + +/** + * Utility class which encapsulates all useful static methods. + */ +public class LocalRandom { + private static int minPauseTime = 3000; + private static int maxPauseTime = 5000; + private static int maxRandomCount = 65536; + + /* + * Return next random double number. + * + * @return random double + */ + public static double random() { + return ThreadLocalRandom.current().nextDouble(); + } + + public static double nextDouble() { + return ThreadLocalRandom.current().nextDouble(); + } + + public static byte nextByte() { + return (byte) nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE); + } + + public static char nextChar() { + return (char) nextInt(Character.MIN_VALUE, Character.MAX_VALUE); + } + + public static short nextShort() { + return (short) nextInt(Short.MIN_VALUE, Short.MAX_VALUE); + } + + public static boolean nextBoolean() { + return ThreadLocalRandom.current().nextBoolean(); + } + + public static void nextBytes(byte[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + byte hash = 0; + byte b; + for (int i = 0; i < arr.length - k; i += k) { + b = nextByte(); + arr[i] = b; + hash ^= b; + } + arr[arr.length - k] = hash; + } + + public static void validate(byte[] arr) { + int k = Math.max(1, arr.length / maxRandomCount); + byte hash = 0; + for (int i = 0; i < arr.length; i += k) { + hash ^= arr[i]; + } + if (hash != 0) { + throw new TestFailure( + "Validation failure: " + arr.getClass() + " hash: " + hash); + } + } + + public static void nextShorts(short[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + short hash = 0; + short s; + for (int i = 0; i < arr.length - k; i += k) { + s = nextShort(); + arr[i] = s; + hash ^= s; + } + arr[arr.length - k] = hash; + } + + public static void validate(short[] arr) { + int k = Math.max(1, arr.length / maxRandomCount); + short hash = 0; + for (int i = 0; i < arr.length; i += k) { + hash ^= arr[i]; + } + if (hash != 0) { + throw new TestFailure( + "Validation failure: " + arr.getClass() + " hash: " + hash); + } + } + + public static void nextChars(char[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + char hash = 0; + char c; + for (int i = 0; i < arr.length - k; i += k) { + c = nextChar(); + arr[i] = c; + hash ^= c; + } + arr[arr.length - k] = hash; + } + + public static void validate(char[] arr) { + int k = Math.max(1, arr.length / maxRandomCount); + char hash = 0; + for (int i = 0; i < arr.length; i += k) { + hash ^= arr[i]; + } + if (hash != 0) { + throw new TestFailure( + "Validation failure: " + arr.getClass() + " hash: " + hash); + } + } + + public static void nextInts(int[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + int hash = 0; + int in; + for (int i = 0; i < arr.length - k; i += k) { + in = nextInt(); + hash ^= in; + arr[i] = in; + } + arr[arr.length - k] = hash; + } + + public static void validate(int[] arr) { + int k = Math.max(1, arr.length / maxRandomCount); + int hash = 0; + for (int i = 0; i < arr.length; i += k) { + hash ^= arr[i]; + } + if (hash != 0) { + throw new TestFailure( + "Validation failure: " + arr.getClass() + " hash: " + hash); + } + } + + public static void nextBooleans(boolean[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + boolean hash = false; + boolean b; + for (int i = 0; i < arr.length - k; i += k) { + b = nextBoolean(); + hash ^= b; + arr[i] = b; + } + arr[arr.length - k] = hash; + } + + public static void validate(boolean[] arr) { + int k = Math.max(1, arr.length / maxRandomCount); + boolean hash = false; + for (int i = 0; i < arr.length; i += k) { + hash ^= arr[i]; + } + if (hash != false) { + throw new TestFailure( + "Validation failure: " + arr.getClass() + " hash: " + hash); + } + } + + public static void nextLongs(long[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + long hash = 0; + long l; + for (int i = 0; i < arr.length - k; i += k) { + l = nextLong(); + hash ^= l; + arr[i] = l; + } + arr[arr.length - k] = hash; + } + + public static void validate(long[] arr) { + int k = Math.max(1, arr.length / maxRandomCount); + long hash = 0; + for (int i = 0; i < arr.length; i += k) { + hash ^= arr[i]; + } + if (hash != 0) { + throw new TestFailure( + "Validation failure: " + arr.getClass() + " hash: " + hash); + } + } + + public static void nextFloats(float[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + for (int i = 0; i < arr.length - k; i += k) { + arr[i] = nextFloat(); + } + } + + public static void validate(float[] arr) { + } + + public static void nextDoubles(double[] arr) { + if (arr.length == 0) { + return; + } + int k = Math.max(1, arr.length / maxRandomCount); + for (int i = 0; i < arr.length - k; i += k) { + arr[i] = nextDouble(); + } + } + + public static void validate(double[] arr) { + } + + public static int nextInt() { + return ThreadLocalRandom.current().nextInt(); + } + + /** + * Return next integer value from 0..n range. + * + * @param n maximum value + * @return random integer + */ + public static int nextInt(int n) { + return ThreadLocalRandom.current().nextInt(n); + } + + public static long nextLong() { + return ThreadLocalRandom.current().nextLong(); + } + + /** + * Return next random integer from min..max range. + * + * @param min minimum value + * @param max maximum value + * @return random integer + */ + public static int nextInt(int min, int max) { + return min + nextInt(max - min); + } + + /** + * Return next random float number. + * + * @return random double + */ + public static float nextFloat() { + return ThreadLocalRandom.current().nextFloat(); + } + + /** + * Return random pause time. + */ + public static long randomPauseTime() { + return nextInt(minPauseTime, maxPauseTime); + } + + /** + * Set minimum pause time. + * + * @param minPauseTime minimum pause time + */ + public static void setMinPauseTime(int minPauseTime) { + LocalRandom.minPauseTime = minPauseTime; + } + + /** + * Set maximum pause time. + * + * @param maxPauseTime maximum pause time + */ + public static void setMaxPauseTime(int maxPauseTime) { + LocalRandom.maxPauseTime = maxPauseTime; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/StressOptions.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/StressOptions.java new file mode 100644 index 00000000000..1d8efa2cfa5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/StressOptions.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +import java.io.PrintStream; +import vm.share.options.Option; + +/** + * Options for stress tests. + * + * The following options may be configured: + * + * -stressTime [time] execution time in seconds + * -stressIterationsFactor [factor] iterations factor. + * The actual number of iterations is obtained by multiplying standard + * number of iterations (which is defined by the test itself) and this factor. + * -stressThreadsFactor [factor] number of threads factor + * The actual number of threads is determined by multiplying standard + * number of threads (which is determined by test itself and may also depend + * on machine configuration) and this factor. + */ +public class StressOptions { + /** + * This enum contains names of stress options + */ + public static enum StressOptionsParam { + stressTime, + stressIterationsFactor, + stressThreadsFactor, + stressRunsFactor, + stressDebug, + stressDebugDetailed, + } + + /* Execution time in seconds */ + @Option(name = "stressTime", default_value = "60", description = "Stress execution time in seconds") + private long time; + + /* Iterations factor */ + @Option(name = "stressIterationsFactor", default_value = "1", description = "Stress iterations factor") + private int iterationsFactor; + + /* Number of threads factor */ + @Option(name = "stressThreadsFactor", default_value = "1", description = "Stress threads factor") + private int threadsFactor; + + @Option(name = "stressRunsFactor", default_value = "1", description = "Times to re-run the test (if supported by the test)") + private int runsFactor; + + /* Debug stress execution */ + @Option(name = "stressDebugEnabled", default_value = "false", description = "Stress debug execution enabled") + private boolean debugEnabled = false; + + /* Detailed stressExecution */ + @Option(name = "stressDebugDetailed", default_value = "false", description = "Stress debug detailed enabled") + private boolean debugDetailed = false; + + /** + * Create StressOptions with default settings. + */ + public StressOptions() { + time = 60; + iterationsFactor = 1; + threadsFactor = 1; + runsFactor = 1; + } + + /** + * Create StressOptions configured from command line arguments. + * + * @param arg arguments + */ + public StressOptions(String[] args) { + this(); + parseCommandLine(args); + } + + /** + * Create stresser with same parameters as another. + * + * @param other another instance of StressOptions + */ + public StressOptions(StressOptions other) { + this.time = other.time; + this.iterationsFactor = other.iterationsFactor; + this.threadsFactor = other.threadsFactor; + this.runsFactor = other.runsFactor; + } + + public static boolean isValidStressOption(String option) { + for (int i = 0; i < StressOptions.StressOptionsParam.values().length; i++) { + if (option.equals(StressOptions.StressOptionsParam.values()[i].name())) + return true; + } + + return false; + } + + /** + * Parse command line options related to stress. + * + * Other options are ignored. + * + * @param args arguments + */ + public void parseCommandLine(String[] args) { + int i = 0; + while (i < args.length) { + String arg = args[i]; + String value = null; + + int eqPos = arg.indexOf('='); + if (eqPos != -1) { + value = arg.substring(eqPos + 1); + arg = arg.substring(0, eqPos); + } + + if (arg.equals("-stressTime")) { + try { + if (value == null) { + if (++i >= args.length) + error("Missing value of -stressTime parameter"); + value = args[i]; + } + time = Long.parseLong(value); + if (time < 0) { + error("Invalid value of -stressTime parameter: " + time); + } + } catch (NumberFormatException e) { + error("Invalid value of -stressTime parameter: " + value); + } + } else if (arg.equals("-stressIterationsFactor")) { + try { + if ( value == null ) { + if (++i >= args.length) { + error("Missing value of -stressIterationsFactor parameter"); + } + value = args[i]; + } + iterationsFactor = Integer.parseInt(value); + if (iterationsFactor <= 0) { + error("Invalid value of -stressIterationsFactor parameter: " + threadsFactor); + } + } catch (NumberFormatException e) { + error("Invalid value of -stressIterationsFactor parameter: " + value); + } + } else if (arg.equals("-stressThreadsFactor")) { + try { + if ( value == null ) { + if (++i >= args.length) { + error("Missing value of -stressThreadsFactor parameter"); + } + value = args[i]; + } + threadsFactor = Integer.parseInt(value); + if (threadsFactor <= 0) { + error("Invalid value of -stressThreadsFactor parameter: " + threadsFactor); + } + } catch (NumberFormatException e) { + error("Invalid value of -stressThreadsFactor parameter: " + value); + } + } else if (arg.equals("-stressRunsFactor")) { + try { + if (value == null) { + if (++i >= args.length) { + error("Missing value of -stressRunsFactor parameter"); + } + value = args[i]; + } + runsFactor = Integer.parseInt(value); + if (runsFactor <= 0) { + error("Invalid value of -stressRunsFactor parameter: " + threadsFactor); + } + } catch (NumberFormatException e) { + error("Invalid value of -stressRunsFactor parameter: " + value); + } + } else if (arg.equals("-stressDebug")) { + debugEnabled = true; + } else if (arg.equals("-stressDebugDetailed")) { + debugDetailed = true; + } + + ++i; + } + } + + /** + * Display information about stress options. + * + * @param out output stream + */ + public void printInfo(PrintStream out) { + out.println("Stress time: " + time + " seconds"); + out.println("Stress iterations factor: " + iterationsFactor); + out.println("Stress threads factor: " + threadsFactor); + out.println("Stress runs factor: " + runsFactor); + } + + private void error(String msg) { + throw new IllegalArgumentException(msg); + } + + /** + * Obtain execution time in seconds. + * + * @return time + */ + public long getTime() { + return time; + } + + /** + * Obtain iterations factor. + * + * @return iterations factor + */ + public int getIterationsFactor() { + return iterationsFactor; + } + + /** + * Obtain threads factor. + * + * @return threads factor + */ + public int getThreadsFactor() { + return threadsFactor; + } + + /** + * Obtain runs factor. + * + * @return runs factor + */ + public int getRunsFactor() { + return runsFactor; + } + + /** + * Determine if debugging of stress execution is set. + * + * @return true if debugging stress execution + */ + public boolean isDebugEnabled() { + return debugEnabled; + } + + /** + * Determine if detailed debugging of stress execution is set. + * + * @return true if detailed debugging is enabled + */ + public boolean isDebugDetailed() { + return debugDetailed; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java new file mode 100644 index 00000000000..ad5c8183672 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +import java.io.PrintStream; +import nsk.share.TestBug; + +/** + * Support class for implementing configurable stress execution. + * + * This class is intended to be used in one thread + * + * + * Stresser stresser = new Stresser(stressOptions); + * + * try { + * stresser.start(100); + * while (stresser.iteration()) { + * ... + * } + * } finally { + * stresser.finish(); + * } + * + * + * Standard number of iterations (integer parameter to start() method) is + * defined by particular test itself. It may be different for different tests + * because average execution time of one iteration may be different. + * This is value which is enough to do what test intends to do and it should + * also give average execution time on most configurations less than + * standard value of stressTime parameter (60 seconds). + * + * @see nsk.share.test.StressOptions for explanation of stress options. + */ +public class Stresser implements ExecutionController { + + private StressOptions options; + private String name; + private long maxIterations; + private long iterations; + private long startTime; + private long finishTime; + private long currentTime; + private PrintStream defaultOutput = System.out; + + /* + * Flag which indicates that execution is finished. + * Volatile, because another thread might read this variable. + */ + private volatile boolean finished; + + /* + * Flag which indicates that execution should be forced to finish. + * Volatile, because another thread might set this variable. + */ + private volatile boolean forceFinish; + + /** + * Creates stresser with default settings. + */ + public Stresser() { + this(new StressOptions()); + } + + /** + * Creates stresser with given options. + * + * @param options stress options + */ + public Stresser(StressOptions options) { + setOptions(options); + } + + /** + * Create stresser configured from command line arguments. + * + * @param arg arguments + */ + public Stresser(String[] args) { + this(new StressOptions(args)); + } + + /** + * Creates stresser configured from command line arguments and + * sets its output stream to a given one + * + * @param arg arguments + * @param out default output stream + */ + public Stresser(String[] args, PrintStream out) { + this(new StressOptions(args)); + setDefaultOutput(out); + } + + /** + * Creates stresser with default options and given name. + * + * @param name stresser name + */ + public Stresser(String name) { + this(); + setName(name); + } + + /** + * Creates stresser with given name and options. + * + * @param name stresser name + * @param options stress options + */ + public Stresser(String name, StressOptions options) { + this(options); + setName(name); + } + + /** + * Creates stresser with given name from command line arguments. + * + * @param name stresser name + * @param args arguments + */ + public Stresser(String name, String[] args) { + this(args); + setName(name); + } + + /** + * Sets default output stream for printing debug messages. + * Initially it is set to System.out. + * + * @param out The stream to print to + */ + public void setDefaultOutput(PrintStream out) { + defaultOutput = out; + } + + /** + * Displays information about stress options. + */ + public void printStressOptions(PrintStream out) { + options.printInfo(out); + } + + /** + * Displays information about this stresser. + * + * @param out output stream + */ + public void printStressInfo(PrintStream out) { + println(out, "Stress time: " + options.getTime() + " seconds"); + println(out, "Iterations: " + maxIterations); + } + + /** + * Displays information about this particular execution + * of this stresser. + * + * @param out output stream + */ + public void printExecutionInfo(PrintStream out) { + println(out, "Completed iterations: " + iterations); + println(out, "Execution time: " + (currentTime - startTime) + " seconds"); + if (!finished) { + println(out, "Execution is not finished yet"); + } else if (forceFinish) { + println(out, "Execution was forced to finish"); + } else if (maxIterations != 0 && iterations >= maxIterations) { + println(out, "Execution finished because number of iterations was exceeded: " + iterations + " >= " + maxIterations); + } else if (finishTime != 0 && currentTime >= finishTime) { + println(out, "Execution finished because time was exceeded: " + (currentTime - startTime) + " >= " + (finishTime - startTime)); + } + } + + private void println(PrintStream out, String s) { + if (name != null) { + out.print(name); + out.print(": "); + } + out.println(s); + out.flush(); + } + + /** + * Starts stress execution. + * + * @param stdIterations standard number of iterations. + */ + public void start(long stdIterations) { + maxIterations = stdIterations * options.getIterationsFactor(); + iterations = 0; + long stressTime = options.getTime(); + startTime = System.currentTimeMillis(); + if (stressTime == 0) { + finishTime = 0; + } else { + finishTime = startTime + stressTime * 1000; + } + finished = false; + forceFinish = false; + if (options.isDebugEnabled()) { + println(defaultOutput, "Starting stress execution: " + stdIterations); + printStressInfo(defaultOutput); + } + } + + /** + * Finishes stress execution. + * + * This method should be called from the thread where + * execution is performed after the loop. It is also + * recommended that this method is called from + * finally {} block. + */ + public void finish() { + currentTime = System.currentTimeMillis(); + finished = true; + if (options.isDebugEnabled()) { + printExecutionInfo(defaultOutput); + } + } + + /** + * Forces execution to finish. + * + * This method may be called from other thread. + */ + public void forceFinish() { + forceFinish = true; + } + + /** + * Marks the beginning of new iteration. + * + * @return true if execution needs to continue + */ + public boolean iteration() { + ++iterations; + if (options.isDebugDetailed()) { + printExecutionInfo(defaultOutput); + } + return continueExecution(); + } + + /** + * Checks if execution needs to continue. This does not mark new iteration. + * + * @return true if execution needs to continue + */ + public boolean continueExecution() { + currentTime = System.currentTimeMillis(); + if (startTime == 0) { + throw new TestBug("Stresser is not started."); + } + return !forceFinish + && !finished + && (maxIterations == 0 || iterations < maxIterations) + && (finishTime == 0 || currentTime < finishTime); + } + + /** + * Obtains current iteration number. + * + * @return current iteration + */ + public long getIteration() { + return iterations; + } + + /** + * Obtains maximum number of iterations. + * + * @return max number of iterations + */ + public long getMaxIterations() { + return maxIterations; + } + + public long getIterationsLeft() { + if (iterations >= maxIterations) { + return 0; + } else { + return maxIterations - iterations; + } + } + + /** + * Obtains time passed from start of stress execution in milliseconds. + * + * @return time + */ + public long getExecutionTime() { + return System.currentTimeMillis() - startTime; + } + + /** + * Obtains time left till end of execution in milliseconds. + * + * @return time + */ + public long getTimeLeft() { + long current = System.currentTimeMillis(); + if (current >= finishTime) { + return 0; + } else { + return finishTime - current; + } + } + + /** + * Sets stress options for this stresser. + * + * @param options stress options + */ + public void setOptions(StressOptions options) { + this.options = options; + } + + /** + * Sets name of this stresser. + * + * @param name name of stresser + */ + public void setName(String name) { + this.name = name; + } + + /** + * Obtains name of this stresser. + */ + public String getName() { + return name; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Test.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Test.java new file mode 100644 index 00000000000..debf6e30d3f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Test.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +/** + * Test marker interface. + */ +public interface Test extends Runnable { +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestBase.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestBase.java new file mode 100644 index 00000000000..447b9d6a4fb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestBase.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +import nsk.share.log.Log; +import nsk.share.log.LogAware; +import nsk.share.Consts; +import vm.share.options.OptionSupport; +import vm.share.options.Option; +import vm.share.options.Options; + +public abstract class TestBase implements Test, LogAware, TestExitCode { + @Option + protected Log log; + protected volatile int exitCode = 0; + + public final void setLog(Log log) { + this.log = log; + } + + public final int getExitCode() { + return exitCode; + } + + public final void setExitCode(int exitCode) { + this.exitCode = exitCode; + } + + public final void setFailed(boolean failed) { + setExitCode(Consts.JCK_STATUS_BASE + (failed ? Consts.TEST_FAILED : Consts.TEST_PASSED)); + } + + public final boolean isFailed() { + return exitCode != 0 && exitCode != 95; + } + + public static void runTest(TestBase test, String[] args) { + OptionSupport.setup(test, args); + test.run(); + int exitCode = test.getExitCode(); + if (exitCode != 0) + System.exit(exitCode); + else + System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestExitCode.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestExitCode.java new file mode 100644 index 00000000000..198d15baa88 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestExitCode.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +/** + * Marker interface to signify that test needs to return exit code. + */ +public interface TestExitCode { + public int getExitCode(); +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestUtils.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestUtils.java new file mode 100644 index 00000000000..1f248de3dc3 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestUtils.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Collection; + +import nsk.share.Failure; +import nsk.share.TestFailure; + +import static java.lang.String.format; + +public class TestUtils { + /** + * @throws nsk.share.Failure with given error message + * + */ + public static void testFailed(Object errorMessage) { + throw new Failure(errorMessage.toString()); + } + + /** + * Checks that expr is true + * + * @throws nsk.share.Failure + * when expr is false + */ + public static void assertTrue(boolean expr, Object errorMessage) { + if (!expr) + testFailed(errorMessage); + } + + /** + * Checks that obj is not null + * + * @throws nsk.share.Failure + * when obj is null + */ + public static void assertNotNull(Object obj, Object errorMessage) { + assertTrue(obj != null, errorMessage); + } + + /** + * Checks that obj1 equal obj2 + * + * @throws nsk.share.Failure + * when obj1 is not equal obj2 + */ + public static void assertEquals(Object obj1, Object obj2, Object errorMessage) { + assertTrue(obj1.equals(obj2), new LazyFormatString("%s: [%s] != [%s]", errorMessage, obj1, obj2)); + } + + public static void assertNotInCollection(Collection list, T value) { + assertTrue(! list.contains(value), new LazyFormatString("Internal error: %s is in collection %s", value, list)); + } + + public static void assertInCollection(Collection list, T value) { + assertTrue(list.contains(value), new LazyFormatString("Internal error: %s is not in collection %s", value, list)); + } + + public static void assertEquals(int i1, int i2) { + if (i1 != i2) { + throw new TestFailure( + format("Check failed: %d != %d", i1, i2)); + } + } + + public static void fail(String msg) { + throw new TestFailure(msg); + } + + public static void assertEquals(String s1, String s2) { + if (s1 == null && s2 == null) { + return; + } + + if (s1 != null && s1.equals(s2)) { + return; + } + + throw new TestFailure(format("Failed: %s != %s", s1, s2)); + } + + /** + * Check that obj is an instance of a class c. + * + * @param obj + * @param c + */ + public static void assertExactClass(Object obj, Class c) { + if (obj.getClass() != c) { + throw new TestFailure(format("Exact class doesn't match: expected: %s; actual: %s", + c.getName(), obj.getClass().getName())); + } + } + /** + * @throws nsk.share.Failure (given exception is set as Failure cause) + * + */ + public static void unexpctedException(Throwable exception) { + throw new Failure("Unexpected exception: " + exception, exception); + } + + public static T[] concatArrays(T[] a1, T[] a2) { + T[] result = Arrays.copyOf(a1, a1.length + a2.length); + System.arraycopy(a2, 0, result, a1.length, a2.length); + return result; + } + + public static T[] concatArrays(T[] a1, T[] a2, T[] a3) { + T[] result = Arrays.copyOf(a1, a1.length + a2.length + a3.length); + System.arraycopy(a2, 0, result, a1.length, a2.length); + System.arraycopy(a3, 0, result, a1.length + a2.length, a3.length); + return result; + } + + public static T[] concatArrays(T a1, T[] a2) { + @SuppressWarnings("unchecked") + T[] result = (T[]) Array.newInstance(a1.getClass(), 1 + a2.length); + result[0] = a1; + System.arraycopy(a2, 0, result, 1, a2.length); + return result; + } + + public static T[] cdr(T[] args) { + return Arrays.copyOfRange(args, 1, args.length); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/Tests.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Tests.java new file mode 100644 index 00000000000..b1755ed47e9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Tests.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.share.test; + +import nsk.share.log.*; +import nsk.share.runner.*; +import nsk.share.TestFailure; + +public class Tests { + protected static class TestRunner { + protected String[] args; + private Log log; + private MultiRunner runner; + private RunParams runParams; + private Test test; + + public TestRunner(Test test, String[] args) { + this.args = args; + this.test = test; + } + + public synchronized Log getLog() { + if (log == null) { + log = new LogSupport(System.out); + } + return log; + } + + private synchronized RunParams getRunParams() { + if (runParams == null) { + runParams = RunParams.getInstance(); + runParams.parseCommandLine(args); + } + return runParams; + } + + public void configure(Object o) { + if (o instanceof LogAware) + ((LogAware) o).setLog(getLog()); + if (o instanceof MultiRunnerAware) + ((MultiRunnerAware) o).setRunner(getRunner()); + if (o instanceof RunParamsAware) + ((RunParamsAware) o).setRunParams(getRunParams()); + } + + private synchronized MultiRunner getRunner() { + if (runner == null) { + runner = new ThreadsRunner(); + configure(runner); + } + return runner; + } + + + public void execute(Object o) { + if (o instanceof Initializable) + ((Initializable) o).initialize(); + int exitCode = 0; + try { + if (o instanceof Runnable) + ((Runnable) o).run(); + if (o instanceof TestExitCode) + exitCode = ((TestExitCode) o).getExitCode(); + } catch (RuntimeException t) { + getLog().error(t); + exitCode = 97; + } + if (exitCode != 95 && exitCode != 0) + throw new TestFailure("Test exit code: " + exitCode); + //System.exit(exitCode); + } + + public void run() { + configure(test); + execute(test); + } + } + + + public static void runTest(Test test, String[] args) { + new TestRunner(test, args).run(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutHandler.java new file mode 100644 index 00000000000..e487d621126 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutHandler.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test.timeoutwatchdog; + +/** + * TimeoutHandler - interface to define reaction on timeout. + * @see TimeoutWatchdoc + */ +public interface TimeoutHandler { + + /** + * Invoked when watchdog detects timeout. Subclasses must implement this method to define how timeout should be handled. + */ + void handleTimeout(); + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutWatchdog.java b/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutWatchdog.java new file mode 100644 index 00000000000..d5f112b33aa --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutWatchdog.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.share.test.timeoutwatchdog; + +import nsk.share.test.ExecutionController; + +/** + * This class watches for ExecutionControler and notifies TimeoutHander in case of timeout. + */ +public class TimeoutWatchdog implements Runnable { + + private ExecutionController executionController; + + private TimeoutHandler handler; + + private static long CHECK_PERIOD = 1000; // In milliseconds + + private TimeoutWatchdog(ExecutionController executionController, TimeoutHandler handler) { + this.executionController = executionController; + this.handler = handler; + } + + /** + * Start watching for timeout. + * This method runs a new daemon thread that checks periodically if the observable test is still running. + * If timeout is detected handler.handleTimeout() will be called. If the test finishes normally the daemon + * thread will silently die. + * @param executionController - executionController used to monitor time left + * @param handler - handler on which handleTimeout() will be called + */ + public static void watch(ExecutionController executionController, TimeoutHandler handler) { + Thread thread = new Thread(new TimeoutWatchdog(executionController, handler)); + thread.setName("TimeoutWatchdog_thread"); + thread.setDaemon(true); + thread.start(); + } + + @Override + public void run() { + try { + while (true) { + Thread.sleep(CHECK_PERIOD); + if (!executionController.continueExecution()) { + System.out.println("Time expired. TimeoutWatchdog is calling TimeoutHandler.handleTimeout."); + handler.handleTimeout(); + } + } + } catch (InterruptedException e) { + throw new RuntimeException("Somebody dared to interrupt TimeoutWatchdog thread."); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/CommentedFileReader.java b/test/hotspot/jtreg/vmTestbase/vm/share/CommentedFileReader.java new file mode 100644 index 00000000000..019d237482c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/CommentedFileReader.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import java.io.*; +import java.util.LinkedList; + +/** + * Utility class intended to read file line by line and skip comments. + */ +public class CommentedFileReader { + + /** + * Type of comments that should be removed from file. + */ + public static enum CommentStyle { + /** + * Comments started with #. + */ + BASH, + /** + * Comments started with //. + */ + JAVA + } + + /** + * Get lines from specified file and filter out comments. + * Only comments in BASH style will be filtered out. + * + * @param path to file that should be readed + * @return filtered lines from file + */ + public static String[] readFile(String path) throws IOException { + return readFile(new File(path), CommentStyle.BASH); + } + + /** + * Get lines from specified file and filter out comments. + * Only comments in BASH style will be filtered out. + * + * @param file that should be readed + * @return filtered lines from file + */ + public static String[] readFile(File file) throws IOException { + return readFile(file, CommentStyle.BASH); + } + + /** + * Get lines from specified file without comments. + * + * @param path to file that should be readed + * @param commentStyle describes what strings will be treated as comments + * @return filtered lines from file + */ + public static String[] readFile(String path, CommentStyle commentStyle) throws IOException { + return readFile(new File(path), commentStyle); + } + + /** + * Get lines from specified file without comments. + * + * @param file that should be readed + * @param commentStyle describes what strings will be treated as comments + * @return filtered lines from file + */ + public static String[] readFile(File file, CommentStyle commentStyle) throws IOException { + LinkedList entries = new LinkedList(); + BufferedReader reader = new BufferedReader(new FileReader(file)); + String commentBeginning; + + switch (commentStyle) { + case BASH: + commentBeginning = "#"; + break; + case JAVA: + commentBeginning = "//"; + break; + default: + throw new IllegalArgumentException("Unknown comment style"); + } + + while (true) { + String entry = reader.readLine(); + if (entry == null) { + break; + } + + entry = entry.replaceAll(commentBeginning + ".*", "").trim(); + + if (entry.length() > 0) { + entries.add(entry); + } + } + + return entries.toArray(new String[entries.size()]); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/FileUtils.java b/test/hotspot/jtreg/vmTestbase/vm/share/FileUtils.java new file mode 100644 index 00000000000..1652e75beaf --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/FileUtils.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + + +public class FileUtils { + + private static ClassLoader cl = ClassLoader.getSystemClassLoader(); + + public static byte[] readFile(File f) throws IOException { + FileInputStream is = new FileInputStream(f); + try { + return readStream(is); + } finally { + is.close(); + } + } + + public static byte[] readClass(String name) throws IOException { + return readResource(name.replace('.', '/') + ".class"); + } + + public static byte[] readResource(String name) throws IOException { + InputStream is = FileUtils.cl.getResourceAsStream(name); + if (is == null) + throw new IOException("Can't read resource " + name); + + try { + return readStream(is); + } finally { + is.close(); + } + } + + public static byte[] readStream(InputStream is) throws IOException { + byte buf[] = new byte[0xFFFF]; + int offset = 0; + int r; + while ((r = is.read(buf, offset, buf.length - offset)) > 0) + offset += r; + return Arrays.copyOf(buf, offset); + } + + public static void writeBytesToFile(File file, byte[] buf) + throws IOException { + FileOutputStream fos = new FileOutputStream(file); + try { + fos.write(buf); + } finally { + fos.close(); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java b/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java new file mode 100644 index 00000000000..6f5f1c0cbcd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Map.Entry; + + +public class InMemoryJavaCompiler { + + public static Map compile(Map inputMap) { + Collection sourceFiles = new LinkedList(); + for (Entry entry : inputMap.entrySet()) { + sourceFiles.add(new SourceFile(entry.getKey(), entry.getValue())); + } + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + FileManager fileManager = new FileManager(compiler.getStandardFileManager(null, null, null)); + + Writer writer = new StringWriter(); + Boolean exitCode = compiler.getTask(writer, fileManager, null, null, null, sourceFiles).call(); + if (!exitCode) { + System.out.println("*********** javac output begin ***********"); + System.out.println(writer.toString()); + System.out.println("*********** javac output end ***********"); + if (writer.toString().contains("java.lang.OutOfMemoryError")) { + System.out.println("Got OOME while performing in memory compilation. It happens on weak hosts and there is nothing we can do. "); + throw new OutOfMemoryError("Got OOME while performing in memory compilation."); + } + throw new RuntimeException("Test bug: in memory compilation failed."); + } + return fileManager.getByteCode(); + } + + // Wraper for class file + static class ClassFile extends SimpleJavaFileObject { + + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + protected ClassFile(String name) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); + } + + @Override + public ByteArrayOutputStream openOutputStream() { return this.baos; } + + byte[] toByteArray() { return baos.toByteArray(); } + } + + // File manager which spawns ClassFile instances by demand + static class FileManager extends ForwardingJavaFileManager { + + private Map classesMap = new HashMap(); + + protected FileManager(JavaFileManager fileManager) { + super(fileManager); + } + + @Override + public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) { + ClassFile classFile = new ClassFile(name); + classesMap.put(name, classFile); + return classFile; + } + + public Map getByteCode() { + Map result = new HashMap(); + for (Entry entry : classesMap.entrySet()) { + result.put(entry.getKey(), entry.getValue().toByteArray()); + } + return result; + } + } + + // Wrapper for source file + static class SourceFile extends SimpleJavaFileObject { + + private CharSequence sourceCode; + + public SourceFile(String name, CharSequence sourceCode) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.sourceCode = sourceCode; + } + + @Override + public CharSequence getCharContent(boolean ignore) { + return this.sourceCode; + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.c b/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.c new file mode 100644 index 00000000000..2b3bf8db6be --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#include "jni.h" +#include "native_thread.h" +#ifdef _WIN32 +#include +#include +#include +#include +#else /* _WIN32 */ +#include +#include +#endif /* _WIN32 */ +#include "jni_tools.h" + +/* + * Class: vm_share_ProcessUtils + * Method: sendSignal + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_sendSignal +(JNIEnv *env, jclass class, jint signalNum) { +#ifdef _WIN32 +/* TODO TODO TODO + int dw; + LPVOID lpMsgBuf; + if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) { + dw = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + printf("%s\n", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + return JNI_FALSE; + } + */ + return JNI_TRUE; +#else /* _WIN32 */ + if (kill(getpid(), signalNum) < 0) + return JNI_FALSE; + return JNI_TRUE; +#endif /* _WIN32 */ +} + +/* + * Class: vm_share_ProcessUtils + * Method: sendCtrlBreak + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_sendCtrlBreak +(JNIEnv *env, jclass class) { +#ifdef _WIN32 + int dw; + LPVOID lpMsgBuf; + if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) { + dw = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + printf("%s\n", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + return JNI_FALSE; + } + return JNI_TRUE; +#else /* _WIN32 */ + if (kill(getpid(), SIGQUIT) < 0) + return JNI_FALSE; + return JNI_TRUE; +#endif /* _WIN32 */ +} + +#ifdef _WIN32 +static BOOL (WINAPI *_MiniDumpWriteDump) ( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); +void reportLastError(const char *msg) { + long errcode = GetLastError(); + if (errcode != 0) { + DWORD len = 0; + char *buf; + size_t n = (size_t)FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + errcode, + 0, + (LPSTR) &buf, + (DWORD)len, + NULL); + if (n > 3) { + /* Drop final '.', CR, LF */ + if (buf[n - 1] == '\n') n--; + if (buf[n - 1] == '\r') n--; + if (buf[n - 1] == '.') n--; + buf[n] = '\0'; + } + printf("%s: %s\n", msg, buf); + LocalFree(buf); + } +} + +#endif /* _WIN32 */ + +jboolean doDumpCore() { +#ifdef _WIN32 + char path[MAX_PATH]; + DWORD size; + DWORD pathLen = (DWORD) sizeof(path); + HINSTANCE dbghelp; + MINIDUMP_EXCEPTION_INFORMATION* pmei; + + HANDLE hProcess = GetCurrentProcess(); + DWORD processId = GetCurrentProcessId(); + HANDLE dumpFile; + MINIDUMP_TYPE dumpType; + static const char* cwd; + static const char* name = "DBGHELP.DLL"; + + printf("# TEST: creating Windows minidump...\n"); + if ((size = GetSystemDirectory(path, pathLen)) > 0) { + strcat(path, "\\"); + strcat(path, name); + dbghelp = LoadLibrary(path); + if (dbghelp == NULL) + reportLastError("Load DBGHELP.DLL from system directory"); + } else { + printf("GetSystemDirectory returned 0\n"); + } + + // try Windows directory + if (dbghelp == NULL && ((size = GetWindowsDirectory(path, pathLen)) > 6)) { + strcat(path, "\\"); + strcat(path, name); + dbghelp = LoadLibrary(path); + if (dbghelp == NULL) { + reportLastError("Load DBGHELP.DLL from Windows directory"); + } + } + if (dbghelp == NULL) { + printf("Failed to load DBGHELP.DLL\n"); + return JNI_FALSE; + } + + _MiniDumpWriteDump = ( + BOOL(WINAPI *)( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION)) GetProcAddress(dbghelp, "MiniDumpWriteDump"); + + if (_MiniDumpWriteDump == NULL) { + printf("Failed to find MiniDumpWriteDump() in module dbghelp.dll"); + return JNI_FALSE; + } + dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData); + + // Older versions of dbghelp.h doesn't contain all the dumptypes we want, dbghelp.h with + // API_VERSION_NUMBER 11 or higher contains the ones we want though +#if API_VERSION_NUMBER >= 11 + dumpType = (MINIDUMP_TYPE)(dumpType | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | + MiniDumpWithUnloadedModules); +#endif + + dumpFile = CreateFile("core.mdmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (dumpFile == INVALID_HANDLE_VALUE) { + reportLastError("Failed to create file for dumping"); + return JNI_FALSE; + } + pmei = NULL; + + + // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all + // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. + if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == FALSE && + _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == FALSE) { + reportLastError("Call to MiniDumpWriteDump() failed"); + return JNI_FALSE; + } + + CloseHandle(dumpFile); + printf("# TEST: minidump created\n"); + // Emulate Unix behaviour - exit process. + ExitProcess(137); + + return JNI_TRUE; +#else /* _WIN32 */ + if (kill(getpid(), SIGSEGV) < 0) + return JNI_FALSE; + return JNI_TRUE; +#endif /* _WIN32 */ + +} + +/* + * Class: vm_share_ProcessUtils + * Method: dumpCore + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_dumpCore + (JNIEnv *env, jclass class) +{ + return doDumpCore(); +} + +/* + * Class: vm_share_ProcessUtils + * Method: getPid + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_vm_share_ProcessUtils_getPid + (JNIEnv *env, jclass class) { +#ifdef _WIN32 + return _getpid(); +#else /* _WIN32 */ + return getpid(); +#endif /* _WIN32 */ +} + + +/* + * Class: vm_share_ProcessUtils + * Method: getPid + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_vm_share_ProcessUtils_getWindowsPid + (JNIEnv *env, jclass class, jlong handle) { +#ifdef _WIN32 + return GetProcessId((HANDLE) handle); +#else /* _WIN32 */ + return -1; +#endif /* _WIN32 */ +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.java b/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.java new file mode 100644 index 00000000000..2e9174452fd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; + +import nsk.share.TestBug; + +import com.sun.management.HotSpotDiagnosticMXBean; + +public final class ProcessUtils { + static { + System.loadLibrary("ProcessUtils"); + } + + private ProcessUtils() {} + + /** + * Send Ctrl-\ to java process and Ctrl-Break on Windows. + * This will usually trigger stack dump for all threads and + * may trigger heap dump. + * + * @return true if it was successful + */ + public static native boolean sendCtrlBreak(); + + /** + * Send any signal to java process on Unix. It currently does nothing on Windows. + * + * @return true if it was successful + */ + public static native boolean sendSignal(int signalNum); + + /** + * Force java process to dump core. + * + * This is done by sending SIGSEGV on unix systems. + * + * @return true if it was successful, false if not (for example on Windows) + */ + public static native boolean dumpCore(); + + /** + * Get PID of java process. + * + * @return PID + */ + public static native int getPid(); + + public static int getPid(Process process) { + Throwable exception; + try { + Field pidField = process.getClass().getDeclaredField("pid"); + pidField.setAccessible(true); + return ((Integer) pidField.get(process)).intValue(); + } catch (NoSuchFieldException e) { + exception = e; + } catch (IllegalAccessException e) { + exception = e; + } + // Try to get Windows handle + try { + Field handleField = process.getClass().getDeclaredField("handle"); + handleField.setAccessible(true); + long handle = ((Long) handleField.get(process)).longValue(); + return getWindowsPid(handle); + } catch (NoSuchFieldException e) { + exception = e; + } catch (IllegalAccessException e) { + exception = e; + } + throw new TestBug("Unable to determine pid from process class " + process.getClass(), exception); + } + + private static native int getWindowsPid(long handle); + + @SuppressWarnings("restriction") + public static void dumpHeapWithHotspotDiagnosticMXBean(String fileName) throws IOException { + System.err.println("Dumping heap to " + fileName); + + File f = new File(fileName); + if (f.exists()) + f.delete(); + + HotSpotDiagnosticMXBean b = ManagementFactory.getPlatformMXBeans( + com.sun.management.HotSpotDiagnosticMXBean.class).get(0); + b.dumpHeap(fileName, false); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/RandomEx.java b/test/hotspot/jtreg/vmTestbase/vm/share/RandomEx.java new file mode 100644 index 00000000000..3d4782114b8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/RandomEx.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class RandomEx extends Random { + private final Map, Supplier> map = new HashMap<>(); + + { + map.put(Boolean.class, this::nextBoolean); + map.put(boolean.class, this::nextBoolean); + map.put(Byte.class, this::nextByte); + map.put(byte.class, this::nextByte); + map.put(Short.class, this::nextShort); + map.put(short.class, this::nextShort); + map.put(Character.class, this::nextChar); + map.put(char.class, this::nextChar); + map.put(Integer.class, this::nextInt); + map.put(int.class, this::nextInt); + map.put(Long.class, this::nextLong); + map.put(long.class, this::nextLong); + map.put(Float.class, this::nextFloat); + map.put(float.class, this::nextFloat); + map.put(Double.class, this::nextDouble); + map.put(double.class, this::nextDouble); + } + + public RandomEx() { + } + + public RandomEx(long seed) { + super(seed); + } + + public byte nextByte() { + return (byte) next(Byte.SIZE); + } + + public short nextShort() { + return (short) next(Short.SIZE); + } + + public char nextChar() { + return (char) next(Character.SIZE); + } + + public T next(Predicate p, T dummy) { + T result; + do { + result = next(dummy); + } while (!p.test(result)); + return result; + } + + @SuppressWarnings("unchecked") + public T next(T dummy) { + Supplier supplier = map.get(dummy.getClass()); + if (supplier == null) { + throw new IllegalArgumentException("supplier for <" + + dummy.getClass() + ">is not found"); + } + return (T) supplier.get(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/StringUtils.java b/test/hotspot/jtreg/vmTestbase/vm/share/StringUtils.java new file mode 100644 index 00000000000..56439538693 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/StringUtils.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import java.io.ByteArrayOutputStream; +import java.util.Random; +import java.util.function.Predicate; + +public class StringUtils { + + public static byte[] binaryReplace(final byte[] src, String search, + String replacement) { + if (search.length() == 0) + return src; + + int nReplaced = 0; + + try { + final byte[] bSrch = search.getBytes("ASCII"); + final byte[] bRepl = replacement.getBytes("ASCII"); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + searching: for (int i = 0; i < src.length; i++) { + if (src[i] == bSrch[0]) { + replacing: do { + for (int ii = 1; ii < Math.min(bSrch.length, + src.length - i); ii++) + if (src[i + ii] != bSrch[ii]) + break replacing; + + out.write(bRepl); + i += bSrch.length - 1; + nReplaced++; + continue searching; + } while (false); + } + + out.write(src[i]); + } + + return out.toByteArray(); + + } finally { + out.close(); + } + } catch (Exception e) { + RuntimeException t = new RuntimeException("Test internal error"); + t.initCause(e); + throw t; + } + } + + public static String generateString(Random rng, int length, + Predicate predicate) { + if (length <= 0) { + throw new IllegalArgumentException("length <= 0"); + } + StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; ++i) { + char tmp; + do { + tmp = (char) rng.nextInt(Character.MAX_VALUE); + } while (!predicate.test(tmp)); + builder.append(tmp); + } + return builder.toString(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/UnsafeAccess.java b/test/hotspot/jtreg/vmTestbase/vm/share/UnsafeAccess.java new file mode 100644 index 00000000000..79a0a7392de --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/UnsafeAccess.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import java.lang.reflect.Field; + +import jdk.internal.misc.Unsafe; + +@SuppressWarnings("restriction") +public class UnsafeAccess { + public static Unsafe unsafe; + + static { + try { + unsafe = Unsafe.getUnsafe(); + } catch ( Exception e ) { + e.printStackTrace(); + } + } + + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/VMRuntimeEnvUtils.java b/test/hotspot/jtreg/vmTestbase/vm/share/VMRuntimeEnvUtils.java new file mode 100644 index 00000000000..85cab7a06db --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/VMRuntimeEnvUtils.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +import java.lang.management.ManagementFactory; +import java.util.Objects; + +public class VMRuntimeEnvUtils { + private static HotSpotDiagnosticMXBean DIAGNOSTIC_BEAN + = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + + private VMRuntimeEnvUtils() { + } + + public static boolean isJITEnabled() { + boolean isJITEnabled = ManagementFactory.getCompilationMXBean() != null; + + return isJITEnabled; + } + + /** + * Returns value of VM option. + * + * @param name option's name + * @return value of option or {@code null}, if option doesn't exist + * @throws NullPointerException if name is null + * @see HotSpotDiagnosticMXBean#getVMOption(String) + */ + public static String getVMOption(String name) { + Objects.requireNonNull(name); + VMOption tmp; + try { + tmp = DIAGNOSTIC_BEAN.getVMOption(name); + } catch (IllegalArgumentException e) { + tmp = null; + } + return (tmp == null ? null : tmp.getValue()); + } + + /** + * Returns value of VM option or default value. + * + * @param name option's name + * @param defaultValue default value + * @return value of option or {@code defaultValue}, if option doesn't exist + * @throws NullPointerException if name is null + * @see #getVMOption(String) + */ + public static String getVMOption(String name, String defaultValue) { + String result = getVMOption(name); + return result == null ? defaultValue : result; + } + + /** + * Returns if a boolean VM option is enabled or not. + * + * @param name option's name + * @return true iff enabled + * @throws IllegalArgumentException if naming non-boolean or non-existing option + */ + public static boolean isVMOptionEnabled(String name) { + String isSet = getVMOption(name, "error"); + if (isSet.equals("true")) { + return true; + } else if (isSet.equals("false")) { + return false; + } + throw new IllegalArgumentException(name + " is not a boolean option."); + } + + /** + * Sets a specified value for VM option of given name. + * + * @param name option's name + * @param value new value + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if new value is invalid or if vm option + * is not writable. + * @see HotSpotDiagnosticMXBean#setVMOption(String, String) + */ + public static void setVMOption(String name, String value) { + Objects.requireNonNull(name); + DIAGNOSTIC_BEAN.setVMOption(name, value); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingHeap.java b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingHeap.java new file mode 100644 index 00000000000..3b4481e4fe7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingHeap.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.gc; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import nsk.share.TestFailure; +import nsk.share.test.ExecutionController; + +public class TriggerUnloadingByFillingHeap implements TriggerUnloadingHelper { + + public void triggerUnloading(ExecutionController stresser) { + List jvmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments(); + if (jvmArgs.contains("-XX:+ExplicitGCInvokesConcurrent")) { + throw new TestFailure("Test bug! Found -XX:+ExplicitGCInvokesConcurrent in jvm args. TriggerUnloadingByFillingHeap.triggerUnloading will not work!."); + } + + System.out.println("collections invoked: " + provokeGC(stresser)); + System.out.println("collections invoked: " + provokeGC(stresser)); + System.out.println("collections invoked: " + provokeGC(stresser)); + } + + private static long getGCCounter() { + return ManagementFactory.getGarbageCollectorMXBeans().get(1).getCollectionCount(); + } + + private static Random random = new Random(); + + public static byte[] garbage; //make it reference public to avoid compiler optimizations + + private static long provokeGC(ExecutionController stresser) { + long initCounter = getGCCounter(); + ArrayList list = new ArrayList(); + while (getGCCounter() == initCounter && stresser.continueExecution()) { + list.add(new byte[1024]); + + garbage = new byte[1024]; + if (random.nextInt(10) % 10 < 3 && !list.isEmpty()) { + list.remove(0); + } + System.gc(); + } + return getGCCounter() - initCounter; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java new file mode 100644 index 00000000000..15799bbf8a7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.gc; + +import java.util.ArrayList; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import metaspace.stressHierarchy.common.exceptions.GotWrongOOMEException; +import nsk.share.gc.gp.classload.GeneratedClassProducer; +import nsk.share.test.ExecutionController; + +public class TriggerUnloadingByFillingMetaspace implements + TriggerUnloadingHelper { + + private static final int NUMBER_OF_THREADS = 30; + + private static class FillMetaspace { + private volatile boolean gotOOME = false; + private ExecutionController stresser; + private GeneratedClassProducer generatedClassProducer = new GeneratedClassProducer("metaspace.stressHierarchy.common.HumongousClass"); + + public FillMetaspace(ExecutionController stresser) { this.stresser = stresser; } + + private class FillMetaspaceTask implements Callable { + @Override + public Object call() throws Exception { + while (stresser.continueExecution() && ! gotOOME) { + try { + generatedClassProducer.create(-100500); //argument is not used. + } catch (OutOfMemoryError oome) { + if (!isInMetaspace(oome)) { + throw new GotWrongOOMEException("Got OOME in heap while gaining OOME in metaspace. Test result can't be valid."); + } + gotOOME = true; + } + } + return null; + } + } + } + + private static boolean isInMetaspace(OutOfMemoryError error) { + return error.getMessage().trim().toLowerCase().contains("metadata"); + } + + @Override + public void triggerUnloading(ExecutionController stresser) { + try { + FillMetaspace fillMetaspace = new FillMetaspace(stresser); + ArrayList> tasks = new ArrayList>(NUMBER_OF_THREADS); + for (int i = 0; i < NUMBER_OF_THREADS; i++) { + tasks.add(fillMetaspace.new FillMetaspaceTask()); + } + ExecutorService executorService = Executors.newCachedThreadPool(); + try { + executorService.invokeAll(tasks); + } catch (InterruptedException e) { + System.out.println("Process of gaining OOME in metaspace was interrupted."); + e.printStackTrace(); + } + } catch (OutOfMemoryError e) { + if (!isInMetaspace(e)) { + throw new GotWrongOOMEException("Got OOME in heap while gaining OOME in metaspace. Test result can't be valid."); + } + return; + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingHelper.java b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingHelper.java new file mode 100644 index 00000000000..b6458f5865e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingHelper.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.gc; + +import nsk.share.test.ExecutionController; + +public interface TriggerUnloadingHelper { + + public void triggerUnloading(ExecutionController stresser); + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingWithWhiteBox.java b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingWithWhiteBox.java new file mode 100644 index 00000000000..7faf5eadb02 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingWithWhiteBox.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.gc; + + +import sun.hotspot.WhiteBox; +import nsk.share.test.ExecutionController; + +public class TriggerUnloadingWithWhiteBox implements TriggerUnloadingHelper { + + private final static WhiteBox wb = WhiteBox.getWhiteBox(); + + @Override + public void triggerUnloading(ExecutionController stresser) { + wb.fullGC(); + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/libProcessUtils.c b/test/hotspot/jtreg/vmTestbase/vm/share/libProcessUtils.c new file mode 100644 index 00000000000..12dbc8e4787 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/libProcessUtils.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni_tools.c" +#include "nsk_tools.c" +#include "ProcessUtils.c" + diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/MemoryPoolFinder.java b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/MemoryPoolFinder.java new file mode 100644 index 00000000000..ca68beffca6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/MemoryPoolFinder.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.monitoring; + +import java.lang.management.*; + +public enum MemoryPoolFinder { + CODE_CACHE, + EDEN_SPACE, + SURVIVOR_SPACE, + OLD_GEN, + PERM_GEN, + METASPACE, + CLASS_METASPACE; + + public static MemoryPoolMXBean findPool(MemoryPoolFinder pool) { + for(MemoryPoolMXBean candidate : ManagementFactory.getMemoryPoolMXBeans()) { + boolean found = false; + switch(pool) { + case CODE_CACHE: + found = candidate.getName().contains("Code Cache"); + break; + case EDEN_SPACE: + found = candidate.getName().contains("Eden"); + break; + case SURVIVOR_SPACE: + found = candidate.getName().contains("Survivor"); + break; + case OLD_GEN: + found = candidate.getName().contains("Old") || candidate.getName().contains("Tenured"); + break; + case PERM_GEN: + found = candidate.getName().contains("Perm"); + break; + case METASPACE: + found = candidate.getName().contains("Metaspace") && !candidate.getName().contains("Class Metaspace"); + break; + case CLASS_METASPACE: + found = candidate.getName().contains("Class Metaspace"); + break; + } + if (found) return candidate; + } + return null; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryManagerData.java b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryManagerData.java new file mode 100644 index 00000000000..ec58d3d43eb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryManagerData.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.monitoring.data; + +import java.lang.management.*; +import javax.management.*; +import java.io.Serializable; + +public class MemoryManagerData implements MemoryManagerMXBean, Serializable { + private String[] memoryPoolNames; + private String name; + private boolean valid; + + public MemoryManagerData(String[] memoryPoolNames, String name, boolean valid) { + this.memoryPoolNames = memoryPoolNames; + this.name = name; + this.valid = valid; + } + + public MemoryManagerData(MemoryManagerMXBean memoryManager) { + this.memoryPoolNames = memoryManager.getMemoryPoolNames(); + this.name = memoryManager.getName(); + this.valid = memoryManager.isValid(); + } + + public String[] getMemoryPoolNames() { + return memoryPoolNames; + } + + public String getName() { + return name; + } + + public boolean isValid() { + return valid; + } + + public ObjectName getObjectName() { + return null; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryPoolData.java b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryPoolData.java new file mode 100644 index 00000000000..cf2221bf136 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryPoolData.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.monitoring.data; + +import java.lang.management.MemoryPoolMXBean; +import java.io.Serializable; + +public class MemoryPoolData implements Serializable { + private String name; + private boolean valid; + private MemoryUsageData usage; + + public MemoryPoolData(String name, boolean valid, MemoryUsageData usage) { + this.name = name; + this.valid = valid; + } + + public MemoryPoolData(MemoryPoolMXBean memoryManager) { + this.name = memoryManager.getName(); + this.valid = memoryManager.isValid(); + this.usage = new MemoryUsageData(memoryManager.getUsage()); + } + + public String getName() { + return name; + } + + public boolean hasName(String name) { + return this.name.equals(name); + } + + public boolean isValid() { + return valid; + } + + public MemoryUsageData getUsage() { + return usage; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryUsageData.java b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryUsageData.java new file mode 100644 index 00000000000..60b9fababe0 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryUsageData.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.monitoring.data; + +import java.io.Serializable; +import java.lang.management.MemoryUsage; +import nsk.share.log.Log; + +public class MemoryUsageData implements Serializable { + private long init; + private long used; + private long committed; + private long max; + + public MemoryUsageData(long init, long used, long committed, long max) { + this.init = init; + this.used = used; + this.committed = committed; + this.max = max; + } + + public MemoryUsageData(MemoryUsage usage) { + this.init = usage.getInit(); + this.used = usage.getUsed(); + this.committed = usage.getCommitted(); + this.max = usage.getMax(); + } + + public MemoryUsageData(MemoryUsageData usage, MemoryUsageData usage1) { + this.init = usage.getInit() + usage1.getInit(); + this.used = usage.getUsed() + usage1.getUsed(); + this.committed = usage.getCommitted() + usage1.getCommitted(); + this.max = usage.getMax() + usage1.getMax(); + } + + public long getInit() { + return init; + } + + public long getUsed() { + return used; + } + + public long getMax() { + return max; + } + + public long getFree() { + return committed - used; + } + + public long getCommitted() { + return committed; + } + + public void log(Log log) { + log.info(" Init: " + init); + log.info(" Used: " + used); + log.info(" Committed: " + committed); + log.info(" Max: " + max); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicObjectFactory.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicObjectFactory.java new file mode 100644 index 00000000000..57a6dbd0c58 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicObjectFactory.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package vm.share.options; + +import java.util.HashMap; +import java.util.Map; +import nsk.share.TestBug; + +/** + * This class allows user to create an {@link ObjectFactory} implementation + * via @{@link vm.share.options.Factory} annotation. See the source code of + * {@link vm.share.options.test.BasicObjectFactoryUsageExample} and + * {@link vm.share.options.test.ExampleWithNonprimitiveOptions}. + * @see Factory + * @see FClass + * @see ObjectFactory + */ +public class BasicObjectFactory implements ObjectFactory +{ + public String getPlaceholder() + { + return getAnnotaion().placeholder_text(); + } + + public String[] getPossibleValues() + { + return getTypesMap().keySet().toArray(new String[0]); + } + + public String getDescription() + { + return getAnnotaion().description().equals(Factory.defDescription)? null : getAnnotaion().description(); + } + + public String getDefaultValue() + { + return getAnnotaion().default_value().equals(Factory.defDefaultValue)? null : + getAnnotaion().default_value(); + } + + public String getParameterDescription(String key) + { + return getTypesMap().get(key).description(); + } + + + // shouldn't value be named key? + + public T getObject(String value) + { + try + { + @SuppressWarnings(value="unchecked") + T result = (T) getTypesMap().get(value).type().newInstance(); + return result; + } catch (InstantiationException ex) + { + throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex); + } catch (IllegalAccessException ex) + { + throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex); + } + } + + protected Factory getAnnotaion() + { + if(!this.getClass().isAnnotationPresent(Factory.class)) + throw new TestBug(" Found an unnotated BasicObjectFactory subclass."); + Factory factoryAnn = this.getClass().getAnnotation(Factory.class); + return factoryAnn; + } + + protected Map getTypesMap() + { // probably there could be some lazy initialization, but I decided not to deal with that. + FClass[] types = getAnnotaion().classlist(); + Map typesMap = new HashMap(types.length); + for (FClass type : types) + { + typesMap.put(type.key(), type); + } + return typesMap; + + } + + // see ExampleWithNonprimitiveOptions instead. +// public void test() +// { +// if(!this.getClass().isAnnotationPresent(Factory.class)) +// throw new RuntimeException(" Found an unnotated BasicObjectFactory subclass."); +// Factory factoryAnn = this.getClass().getAnnotation(Factory.class); +// System.out.println(" placeholder_text " + factoryAnn.placeholder_text()); +// System.out.println(" default_value " + +// (factoryAnn.default_value().equals(Factory.defDefault_value) ? null : factoryAnn.default_value()) ); +// +// } +// +// @Factory(placeholder_text="number", default_value="test", +// classlist = { +// @FClass( key="int", description="integer", type=int.class), +// @FClass( key="boolean", description="boolean", type=boolean.class) +// } ) +// public static class testOF extends BasicObjectFactory {} +// +//// @Factory(placeholder_text="placehldr1") +//// public static class testOF1 extends BasicObjectFactory {} +// +// +// public static void main(String[] args) +// { +// BasicObjectFactory bof = new testOF(); +// bof.test(); +//// new testOF1().test(); +// +// } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicOptionObjectFactory.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicOptionObjectFactory.java new file mode 100644 index 00000000000..138902532ee --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicOptionObjectFactory.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package vm.share.options; + +import java.util.HashMap; +import java.util.Map; +import nsk.share.TestBug; + +/** + * This class allows user to create an {@link ObjectFactory} implementation + * via @{@link vm.share.options.Factory} annotation. See the source code of + * {@link vm.share.options.test.BasicObjectFactoryUsageExample} and + * {@link vm.share.options.test.ExampleWithNonprimitiveOptions}. + * @see Factory + * @see FClass + * @see ObjectFactory + */ +public class BasicOptionObjectFactory implements OptionObjectFactory +{ + public String getPlaceholder() + { + return getAnnotaion().placeholder_text(); + } + + public String[] getPossibleValues() + { + return getTypesMap().keySet().toArray(new String[0]); + } + + public String getDescription() + { + return getAnnotaion().description().equals(Factory.defDescription)? null : getAnnotaion().description(); + } + + public String getDefaultValue() + { + return getAnnotaion().default_value().equals(Factory.defDefaultValue)? null : + getAnnotaion().default_value(); + } + + public String getParameterDescription(String key) + { + return getTypesMap().get(key).description(); + } + + + // shouldn't value be named key? + + public T getObject(String value) + { + try + { + @SuppressWarnings(value="unchecked") + T result = (T) getTypesMap().get(value).type().newInstance(); + return result; + } catch (InstantiationException ex) + { + throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex); + } catch (IllegalAccessException ex) + { + throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex); + } + } + + protected Factory getAnnotaion() + { + if(!this.getClass().isAnnotationPresent(Factory.class)) + throw new TestBug(" Found an unnotated BasicObjectFactory subclass."); + Factory factoryAnn = this.getClass().getAnnotation(Factory.class); + return factoryAnn; + } + + protected Map getTypesMap() + { // probably there could be some lazy initialization, but I decided not to deal with that. + FClass[] types = getAnnotaion().classlist(); + Map typesMap = new HashMap(types.length); + for (FClass type : types) + { + typesMap.put(type.key(), type); + } + return typesMap; + + } + + // see ExampleWithNonprimitiveOptions instead. +// public void test() +// { +// if(!this.getClass().isAnnotationPresent(Factory.class)) +// throw new RuntimeException(" Found an unnotated BasicObjectFactory subclass."); +// Factory factoryAnn = this.getClass().getAnnotation(Factory.class); +// System.out.println(" placeholder_text " + factoryAnn.placeholder_text()); +// System.out.println(" default_value " + +// (factoryAnn.default_value().equals(Factory.def_default_value) ? null : factoryAnn.default_value()) ); +// +// } +// +// @Factory(placeholder_text="number", default_value="test", +// classlist = { +// @FClass( key="int", description="integer", type=int.class), +// @FClass( key="boolean", description="boolean", type=boolean.class) +// } ) +// public static class testOF extends BasicObjectFactory {} +// +//// @Factory(placeholder_text="placehldr1") +//// public static class testOF1 extends BasicObjectFactory {} +// +// +// public static void main(String[] args) +// { +// BasicObjectFactory bof = new testOF(); +// bof.test(); +//// new testOF1().test(); +// +// } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/FClass.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/FClass.java new file mode 100644 index 00000000000..8a8e9a65fed --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/FClass.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; +import java.lang.annotation.*; +/** + * This is an auxilary declaration for use with @Factory annotation, + * allows to add a particular class to the factory. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FClass +{ +// final public static String def_default_value = "[no default]"; + /** + * A key which tells the BasicObjectFactory to instaniate given class, + * is mandatory. + */ + String key(); // mandatory ; + /** + * Description of this kind of instances, is mandatory. + */ + String description(); + + /** + * The class to instantiate, should have a default public constructor, + * so that type().newInstance() will work, is mandatory. + */ + Class type(); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/Factory.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/Factory.java new file mode 100644 index 00000000000..a7e203c7bfd --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/Factory.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; +import java.lang.annotation.*; +/** + * This annotation is coupled with {@link BasicObjectFactory} class, + * and allows one to create implementations of ObjectFactory via annotations. + *
       a simple example:
      +@Factory(description="dummy factory", default_value="array_list", placeholder_text="a type",
      +classlist={
      +@FClass(description="a linked list", key="linked_list", type=LinkedList.class),
      +@FClass(description="an array  list", key="array_list", type=ArrayList.class)
      +})
      +public class BasicObjectFactoryUsageExample extends BasicObjectFactory
      +{
      +}
      + * 
      + * @see BasicObjectFactory + * @see FClass + * @see vm.share.options.test.BasicObjectFactoryUsageExample + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Factory +{ + final public static String defDefaultValue = "[no factory default]"; + final public static String defDescription = "[no factory description]"; + /** + * Used for generating placeholder text in <..> part of help message, + * is mandatory. + */ + String placeholder_text(); // mandatory ; + /** + * Default value, used if the option is not specified AND if no default + * value has been specified in the corresponding @Option annotation. + */ + String default_value() default defDefaultValue; + + /** + * A help message string for the factory. + */ + String description() default defDescription; + + /** + * The list of classes and keys to instantiate. + * @see FClass + */ + FClass[] classlist(); // mandatory +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/IgnoreUnknownArgumentsHandler.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/IgnoreUnknownArgumentsHandler.java new file mode 100644 index 00000000000..4cfe905ffd7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/IgnoreUnknownArgumentsHandler.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +public class IgnoreUnknownArgumentsHandler implements OptionHandler { + + @Override public void option(String name, String value) {} + @Override public void argument(String value) {} + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/ObjectFactory.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/ObjectFactory.java new file mode 100644 index 00000000000..3c27c273116 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/ObjectFactory.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package vm.share.options; + +/** + * This is a factory interface used to setup non-simple type options, + * implemented by the user, there is a shortcut, see {@link BasicObjectFactory}. + */ +public interface ObjectFactory +{ + /** + * Returns a string that can be used in <..> section of help message. + * @return placeholder text + */ + public String getPlaceholder(); + /** + * Enumerates all possible key values for this factory. + * @return an array of keys + */ + public String[] getPossibleValues(); + + /** + * Returns default description for options which use this factory + * @return the description string. + */ + public String getDescription(); + + + /** + * For a given parameter value gives its description. + * @param key to instantiate parameter + * @return description string for the parameter given. + */ + public String getParameterDescription(String key); + + /** + * Returns default value for the parameter, which is used if + * no default value attribute is defined at the @Option annotation level. + * @return default value for the parameter, null if mandatory + */ + public String getDefaultValue(); + + /** + * Constructs an object given a object type key. + * @param key name indicating the type of the object to create. + * @return the instance of the requested type + */ + public T getObject(String key); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/Option.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/Option.java new file mode 100644 index 00000000000..aa0d38eaf8b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/Option.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; +import java.lang.annotation.*; +/** + * This annotation is the most useful one of the whole API. + * It is used to mark non-static fields of the object and to declare the + * corresponding options. The name of the option defaults to the name of the field. + * The help message for the option should also be also declared + * here (or it could be declared at the {@link ObjectFactory} level at any case it is mandatory). + * For non-simple option types a factory attribute should be provided which + * points to a class which implements {@link ObjectFactory} interface. That factory is + * then used to instantiate an object given the option value and to populate the + * annotated field. + * + * If a default value is provided it is used if the corresponding option is not declared + * at the command line. If it is not provided and there is no option then an error is thrown. + * For non-simple field types default values can be provided at ObjectFactory level. + * See also the documentation at the package level.). + */ +// kept at runtime, applied to fields only. +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Option +{ + // these strings help to find out if the corresponding attribute was not defined. + final public static String defName = "[no name]"; + final public static String defDefaultValue = "[no default]"; + final public static String defDescription = "[no description]"; + + /** + * The name of the option, defaults to the name of the annotated field. + */ + String name() default defName; + /** + * The default value for the option, option is mandatory if it is not specified here + * and at the ObjectFactory level. + */ + String default_value() default defDefaultValue; + /** + * A short description of the option used to generate a help message. + */ + String description() default defDescription; + + /** + * The factory class to use for instantiating the corresponding option. + */ + Class factory() default OptionObjectFactory.class; +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionDefinition.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionDefinition.java new file mode 100644 index 00000000000..08aaa75be86 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionDefinition.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +import java.util.Map; +import java.util.HashMap; +import java.lang.reflect.Field; +import nsk.share.TestBug; + +/** + * This is a "value" class for holding information about the defined options. + */ +public final class OptionDefinition { + private static final Map factories = new HashMap(); + private String prefix; + private String name; + private String description; + private String defaultValue; + private Class factory; + private Field field; + private Object owner; + + public OptionDefinition(String prefix, String name, String description, String defaultValue, Class factory, Field field, Object owner) { + this.prefix = prefix; + this.name = name; + this.description = description; + this.defaultValue = defaultValue; + this.factory = factory; + this.field = field; + this.owner = owner; + } + + public String getPrefix() { + return prefix; + } + + public String getName() { + return name; + } + + public String getFullName() { + if (prefix != null) + return prefix + "." + name; + else + return name; + } + + public Field getField() { + return field; + } + + public Object getOwner() { + return owner; + } + + public String getDescription() { + if (hasFactory()) + if (description == null) + return getFactory().getDescription(); + return description; + } + + public String getDefaultValue() { + if (hasFactory()) + if (defaultValue == null) + return getFactory().getDefaultValue(); + return defaultValue; + } + + public boolean hasFactory() { + return factory != null; + } + + public String getPlaceHolder() { + if (hasFactory()) + return getFactory().getPlaceholder(); + else + return getField().getType().toString(); + } + + public synchronized OptionObjectFactory getFactory() { + if (factory == null) + throw new TestBug("Called getFactory() on OptionDefinition with unset factory"); + OptionObjectFactory factory = factories.get(this.factory); + if (factory == null) { + try { + factory = this.factory.newInstance(); + } catch (InstantiationException ex) { + throw new TestBug("Failed to instantiate factory " + this.factory, ex); + } catch (IllegalAccessException ex) { + throw new TestBug("Failed to instantiate factory " + this.factory, ex); + } + } + return factory; + } + + public String toString() { + return "Option " + name + " field " + field + " object " + owner; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionError.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionError.java new file mode 100644 index 00000000000..6574ea45f8d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionError.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +import nsk.share.TestBug; + +public class OptionError extends TestBug { + public OptionError(String msg, OptionDefinition optDef) { + super(msg + " (option definition: " + optDef + ")"); + } + + public OptionError(String msg, Throwable e, OptionDefinition optDef) { + super(msg + " (option definition: " + optDef + ")", e); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionHandler.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionHandler.java new file mode 100644 index 00000000000..635b904e6cc --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package vm.share.options; + +/** + * Handles options not specified via @Options annotations, + * implemented and provided by the user. + */ +public interface OptionHandler +{ + /** + * This method is called for every unknown option + * @param name option name (not including '-' or '=', trimmed) + * @param value may be null in the case of the last option with no value + * specified. + */ + public void option(String name, String value); + + /** + * This method is called for every command line argument which + * is not recognized as a part of -option_name=value pair. + * @param value the value of an unrecognized argument + */ + public void argument(String value); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionObjectFactory.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionObjectFactory.java new file mode 100644 index 00000000000..d07dad7ad3c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionObjectFactory.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package vm.share.options; + +/** + * This is a factory interface used to setup non-simple type options, + * implemented by the user, there is a shortcut, see {@link BasicObjectFactory}. + */ +public interface OptionObjectFactory +{ + /** + * Returns a string that can be used in <..> section of help message. + * @return placeholder text + */ + public String getPlaceholder(); + + /** + * Enumerates all possible key values for this factory. + * @return an array of keys + */ + public String[] getPossibleValues(); + + /** + * Returns default description for options which use this factory + * @return the description string. + */ + public String getDescription(); + + /** + * For a given parameter value gives its description. + * @param key to instantiate parameter + * @return description string for the parameter given. + */ + public String getParameterDescription(String key); + + /** + * Returns default value for the parameter, which is used if + * no default value attribute is defined at the @Option annotation level. + * @return default value for the parameter, null if mandatory + */ + public String getDefaultValue(); + + /** + * Constructs an object given a object type key. + * @param key name indicating the type of the object to create. + * @return the instance of the requested type + */ + public T getObject(String key); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionSupport.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionSupport.java new file mode 100644 index 00000000000..4fb774c8c3d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionSupport.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +/** + * This class actually provides the OptionFramework API + * via two static {@link OptionSupport#setup} methods. + * See also "General description" section of the package level documentation. + */ +public class OptionSupport +{ + /** + * This method parses the commandline arguments, setups the instance fields (annotated by @Option) accordingly + * and calls method run(). + * @param test the instance to setup fields for + * @param args command line arguments array + */ + public static void setupAndRun(Runnable test, String[] args) { + setupAndRun(test, args, null); + } + + /** + * This method parses the commandline arguments and setups the instance fields (annotated by @Option) accordingly + * @param test the instance to setup fields for + * @param args command line arguments array + */ + public static void setup(Object test, String[] args) + { + setup(test, args, null); + } + + /** + * This method parses the commandline arguments, setups the instance fields (annotated by @Option) accordingly + * and calls method run(). + * @param test the instance to setup fields for + * @param args command line arguments array + * @param unknownOptionHandler an option handler for unknown options + */ + public static void setupAndRun(Runnable test, String[] args, OptionHandler unknownOptionHandler) { + setup(test, args, unknownOptionHandler); + test.run(); + } + + + /** + * This is an extension API which allows Test author to create and + * process some specific options. + * @param test the instance to setup fields for + * @param args command line arguments array + * @param unknownOptionHandler an option handler for unknown options + * + */ + public static void setup(Object test, String[] args, OptionHandler unknownOptionHandler) { + new OptionsSetup(test, args, unknownOptionHandler).run(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/Options.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/Options.java new file mode 100644 index 00000000000..82479f10fe2 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/Options.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** + * This annotation marks fields which should be scanned for @Option annotation, + * see the souurce code of {@link vm.share.options.test.SimpleExampleWithOptionsAnnotation} + * for detailed example. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Options { + // default value for undefined attribute + final public static String defPrefix = "[no prefix]"; + /** + * The name of this group of option, added as prefix + */ + String prefix() default defPrefix; +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsMap.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsMap.java new file mode 100644 index 00000000000..06ab0f4644f --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsMap.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** + * This annotation marks fields of type Map, + * where the name=>value map of given options is placed by the framework + * + * should be stored + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface OptionsMap { } diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsSetup.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsSetup.java new file mode 100644 index 00000000000..cb70db75feb --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsSetup.java @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +import java.util.Map; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Iterator; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.io.PrintStream; +import nsk.share.TestBug; +import nsk.share.log.LogSupport; + +class OptionsSetup { + private LogSupport log = new LogSupport(); + private boolean verbose = true; + private Object test; + private String[] args; + private OptionHandler unknownOptionHandler; + + private int argIndex = 0; + private Map optionDefs = new LinkedHashMap(); // Use LinkedHashMap to ensure order of options + private List unconfiguredOptionsList = new ArrayList(); + private List unconfiguredOptionList = new ArrayList(); + private Map optionValues = new LinkedHashMap(); + + public OptionsSetup(Object test, String[] args, OptionHandler unknownOptionHandler) { + this.test = test; + this.args = args; + this.unknownOptionHandler = unknownOptionHandler; + log.setDebugEnabled(verbose); + } + + public void run() { + searchAnnotations(test, null); + while (argIndex < args.length) { + process1Arg(); + } + setDefaultValues(); + checkMandatoryOptions(); + if (unconfiguredOptionsList.size() > 0) { + for (OptionDefinition optDef : unconfiguredOptionsList) + log.info("Unconfigured option: " + optDef); + throw new TestBug("Some options are unconfigured"); + } + } + + private void checkMandatoryOptions() { + for (Map.Entry e : optionDefs.entrySet()) { + String name = e.getKey(); + OptionDefinition optDef = e.getValue(); + if (optDef.getDefaultValue() == null && !optionValues.containsKey(name)) + throw new TestBug("Mandatory option is not specified: -" + name); + } + } + + private void setDefaultValues() { + for (Iterator it = unconfiguredOptionList.iterator(); it.hasNext(); ) { + OptionDefinition optDef = it.next(); + String value = optDef.getDefaultValue(); + if (value == null) + continue; + setOptionValue(optDef, value); + it.remove(); + if (unconfiguredOptionsList.contains(optDef)) + unconfiguredOptionsList.remove(optDef); + } + + for (Iterator it = unconfiguredOptionsList.iterator(); it.hasNext(); ) { + OptionDefinition optDef = it.next(); + if (optionsAnnotation(optDef.getOwner(), optDef.getField(), null, optDef, true)) + it.remove(); + } + } + + private void process1Arg() { + String arg = args[argIndex++]; + //log.debug("Processing argument: " + arg); + if (!arg.startsWith("-")) { + processUnknownArg(arg); + return; + } + String opt = arg.substring(1); + String value = null; + int i = opt.indexOf('='); + if (i != -1) { + value = opt.substring(i + 1); + opt = opt.substring(0, i); + } + if (opt.equals("help")) { + printHelp(); + throw new TestBug("-help was specified"); + } + if (!optionDefs.containsKey(opt)) { + if (value == null && argIndex < args.length) + value = args[argIndex++]; + // We need to try to resolve default values of all unconfigured fields because one of them may potentially have this option + setDefaultValues(); + if (!optionDefs.containsKey(opt)) { + processUnknownOpt(opt, value); + return; + } + } + OptionDefinition optDef = optionDefs.get(opt); + Field f = optDef.getField(); + // Handle boolean omitted value + if (value == null && (argIndex >= args.length || args[argIndex].startsWith("-"))) { + if (f.getType() == boolean.class || f.getType() == Boolean.class) { + value = "true"; + } + } + if (value == null) { + if (argIndex >= args.length) + throw new TestBug("Missing value for option -" + opt); + value = args[argIndex++]; + } + setOptionValue(optDef, value); + if (unconfiguredOptionList.contains(optDef)){ + unconfiguredOptionList.remove(optDef); + } + } + + private void setOptionValue(OptionDefinition optDef, String value) { + Object ovalue = null; + if (optDef.hasFactory()) { + ovalue = optDef.getFactory().getObject(value); + } else { + ovalue = PrimitiveParser.parse(value, optDef.getField().getType()); + } + optionValues.put(optDef.getName(), ovalue); + try { + Field f = optDef.getField(); + Object o = optDef.getOwner(); + f.set(o, ovalue); + if (f.isAnnotationPresent(Options.class)) { + if (!optionsAnnotation(o, f, optDef.getPrefix(), optDef, false)) + throw new TestBug("Unexpected (bug in framework?): optionsAnnotation returned null: " + optDef); + if (unconfiguredOptionsList.contains(optDef)) + unconfiguredOptionsList.remove(optDef); + } + } catch (IllegalArgumentException e) { + throw new TestBug("Exception setting field value for option " + optDef.getName(), e); + } catch (IllegalAccessException e) { + throw new TestBug("Exception setting field value for option " + optDef.getName(), e); + } + } + + private void processUnknownArg(String arg) { + if (unknownOptionHandler != null) + unknownOptionHandler.argument(arg); + else + throw new TestBug("Invalid argument: " + arg); + } + + private void processUnknownOpt(String opt, String value) { + if (unknownOptionHandler != null) + unknownOptionHandler.option(opt, value); + else + throw new TestBug("Invalid option: '" + opt + "', value: '" + value + "'"); + } + + private void searchAnnotations(Object o, String prefix) { + Class cl0 = o.getClass(); + //log.debug("Looking for annotations for object " + o + ", class " + cl0); + List classes = new LinkedList(); + while (cl0.getSuperclass() != null) { + classes.add(0, cl0); // Add to the beginning to ensure the option order is from superclass to subclass + cl0 = cl0.getSuperclass(); + } + for (Class cl : classes) { + for (Field f : cl.getDeclaredFields()) { + OptionDefinition optDef = null; + if (f.isAnnotationPresent(Option.class)) { + optDef = optionAnnotation(o, f, prefix); + if (optDef != null) { + unconfiguredOptionList.add(optDef); + } + } + if (f.isAnnotationPresent(Options.class)) { + if (!optionsAnnotation(o, f, prefix, optDef, false)) { + if (!unconfiguredOptionsList.contains(optDef)) + unconfiguredOptionsList.add(optDef); + } + } + } + } + } + + private boolean optionsAnnotation(Object o, Field f, String prefix, OptionDefinition optDef, boolean useDefault) { + if (Modifier.isStatic(f.getModifiers())) + throw new OptionError("@Options annotation is not allowed at static field", optDef); + if (!Object.class.isAssignableFrom(f.getDeclaringClass())) + throw new OptionError("@Options annotation is only allowed on object types", optDef); + //log.debug("Processing @Options annotation: object " + o + ", field " + f + ", prefix " + prefix); + Object v = null; + try { + f.setAccessible(true); + v = f.get(o); + } catch (IllegalAccessException e) { + throw new OptionError("Exception getting value of field ", e, optDef); + } + if (v == null) { + if (optDef == null) + throw new OptionError("Value of field is null and no @Option annotation is present", optDef); + if (!optDef.hasFactory()) + throw new OptionError("Value of field is null and no @Option annotation does not have factory", optDef); + if (useDefault) { + setOptionValue(optDef, optDef.getDefaultValue()); + try { + v = f.get(o); + } catch (IllegalAccessException e) { + throw new OptionError("Exception getting value of field ", e, optDef); + } + } + if (v == null) { + // We cannot setup it right away, so it is stored until value is set + return false; + } else + return true; // setOption Value already searched annotations + } + Options opts = f.getAnnotation(Options.class); + String vprefix = opts.prefix(); + if (vprefix.equals(Options.defPrefix)) + vprefix = null; + if (vprefix != null) { + if (prefix != null) + prefix = prefix + "." + vprefix; + else + prefix = vprefix; + } + searchAnnotations(v, prefix); + return true; + } + + private OptionDefinition optionAnnotation(Object o, Field f, String prefix) { + //log.debug("Processing @Option annotation: object " + o + ", field " + f + ", prefix " + prefix); + f.setAccessible(true); + Option opt = f.getAnnotation(Option.class); + String name = opt.name(); + if (name.equals(Option.defName)) + name = f.getName(); // option name defaults to field name + if (prefix != null) + name = prefix + "." + name; + if (optionDefs.containsKey(name)) + throw new TestBug("Option is already defined: " + name); + String defaultValue = opt.default_value(); + if (defaultValue.equals(Option.defDefaultValue)) + defaultValue = null; // default value defaults to null + String description = opt.description(); + if (description.equals(Option.defDescription)) + description = null; + if (description == null) { + if (name.equals("log") || name.endsWith(".log")) { + try { + f.set(o, log); + } catch (IllegalAccessException e) { + throw new TestBug("Exception setting log field of " + o, e); + } + return null; + } else + throw new TestBug("@Option annotation should always have description set: " + name + ", field: " + f); + } + Class factory = opt.factory(); + //log.debug("Factory: " + factory); + if (factory.equals(OptionObjectFactory.class)) + factory = null; + OptionDefinition optDef = new OptionDefinition( + prefix, + name, + description, + defaultValue, + factory, + f, + o + ); + optionDefs.put(name, optDef); + //log.debug("Added option definition: " + optDef); + return optDef; + } + + private void printHelp() { + PrintStream out = System.out; + out.println(" Supported options:"); + out.println(" -help"); + out.println(" Show this help screen"); + for (Map.Entry entry : optionDefs.entrySet()) { + String opt = entry.getKey(); + OptionDefinition optDef = entry.getValue(); + out.println(" -" + opt + " <" + optDef.getPlaceHolder() + ">"); + out.print(" " + optDef.getDescription() + " "); + if (optDef.getDefaultValue() != null) { + out.println("(default: " + optDef.getDefaultValue() + ")"); + } else { + out.println("(mandatory)"); + } + if (optDef.hasFactory()) { + OptionObjectFactory factory = optDef.getFactory(); + for (String key : factory.getPossibleValues()) { + out.println(" " + key + ": " + factory.getParameterDescription(key)); + } + } + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/ParserException.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/ParserException.java new file mode 100644 index 00000000000..256b4a40521 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/ParserException.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.options; + +import nsk.share.TestBug; + +/** + * This class represents a simple Parser exception. + */ +public class ParserException extends TestBug { + public ParserException(String message, Throwable cause) { + super(message, cause); + } + + public ParserException(String message) { + super(message); + } + + public ParserException(Throwable cause) { + super(cause); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/PrimitiveParser.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/PrimitiveParser.java new file mode 100644 index 00000000000..1f232c74346 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/PrimitiveParser.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package vm.share.options; + +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.Map; +import nsk.share.TestBug; + +/** + * A utility class used to parse arguments of various primitive types. + */ +public class PrimitiveParser +{ + /** + * Checks if the parser can handle passed type ("primitive/wrapper" or one-dim array of those). + * Note that one-dim arrays of primitives/strings/wrappers are also supported. + * @param type the type to parse against + * @return true, if can parse. + */ + public static boolean canHandle(Class type) + { + + if(type.isArray()) + { + Class compType = type.getComponentType(); + if(compType.isArray()) return false; // Cannot handle multidimensional arrays + return canHandle(compType); + } + type = convertPrimitiveTypeToWrapper(type); + return parsers.containsKey(type); + } + + /** + * A simple helper method. + * @param type the type to check for + * @return the parser to use, null if there is none. + */ + private static PParser getParser(Class type) + { + return parsers.get(convertPrimitiveTypeToWrapper(type)); + } + + /** + * The main API method of this class. + * @param param the parameter to parse + * @param type parameter type to parse against + * @return returns the object of a given type. + * @throws vm.share.options.PrimitiveParser.ParserException + */ + public static Object parse(String param, Class type) throws ParserException + { + if(type.isArray()) + { + Class compType = type.getComponentType(); + if(compType.isArray()) + throw new ParserException("Cannot handle multidimensional arrays"); + + if(!canHandle(compType)) + throw new ParserException("Unable to parse unknown array component type " + compType); + + String[] params = param.split(","); + Object arr = Array.newInstance(compType, params.length); + for (int i = 0; i < params.length; i++) + { + String par = params[i].trim(); + Array.set(arr, i, parse(par, compType)); + } + return arr; + } + else + { + if(!canHandle(type)) + throw new ParserException("Unable to parse unknown type " + type); + return getParser(type).parse(param); + } + } + + // I'm not sure, if generics are of any use here... + static private abstract class PParser + { + abstract T parse(String param) throws ParserException; + +// Class getClassKey() +// { +// return PrimitiveParser.(Class) T.getClass(); +// } + } + + /** + * Converts primitive types to corresponding wrapper classes. + * We could register int.class, boolean.class etc in the hashtable instead. + * (Or Integer.TYPE, etc.) + * @param type to convert to wrapper + * @return wrapper class or type if it is not primitive + */ + public static Class convertPrimitiveTypeToWrapper(Class type) + { + if(!type.isPrimitive()) return type; + Object arr = Array.newInstance(type, 1); + Object v = Array.get(arr, 0); + return v.getClass(); + } + + + //"kind of state" machine stuff + + private static Map, PParser> parsers; + + static + { + parsers = new HashMap, PrimitiveParser.PParser>(16); + parsers.put(Integer.class, new PParser() + { + @Override Integer parse(String param) throws ParserException + { + if ( param.startsWith("0x") ) + return Integer.parseInt(param.substring(2)); + else + return Integer.valueOf(param); + } + }); + parsers.put(Boolean.class, new PParser() + { + @Override Boolean parse(String param) throws ParserException + { + //special behavior for options + if(param == null) return true; + if(param.trim().length()==0) return true; + return Boolean.valueOf(param); + } + }); + + parsers.put(String.class, new PParser() + { + @Override String parse(String param) throws ParserException + { + if(param == null) throw new ParserException(" Got null value string."); + return param; + } + }); + + + parsers.put(Character.class, new PParser() + { + @Override Character parse(String param) throws ParserException + { + if(param.length()!=1) + throw new TestBug("Found Character type option of length != 1"); + return Character.valueOf(param.charAt(0)); + } + }); + + parsers.put(Byte.class, new PParser() + { + @Override Byte parse(String param) throws ParserException + { + if ( param.startsWith("0x") ) + return Byte.parseByte(param.substring(2)); + else + return Byte.valueOf(param); + } + }); + + parsers.put(Short.class, new PParser() + { + @Override Short parse(String param) throws ParserException + { + if ( param.startsWith("0x") ) + return Short.parseShort(param.substring(2)); + else + return Short.valueOf(param); + } + }); + + parsers.put(Long.class, new PParser() + { + @Override Long parse(String param) throws ParserException + { + if ( param.startsWith("0x") ) + return Long.parseLong(param.substring(2)); + else + return Long.valueOf(param); + } + }); + + parsers.put(Float.class, new PParser() + { + @Override Float parse(String param) throws ParserException + { + return Float.valueOf(param); + } + }); + + parsers.put(Double.class, new PParser() + { + @Override Double parse(String param) throws ParserException + { + return Double.valueOf(param); + } + }); + } + + +/* Discussion + * 1. It was proposed to use instead of the convertPrimitive the following + * + * private static Map, Class> wrapperClasses = new HashMap, Class>(); + * + * so we could do if(type.isPrimitive()) + type = wrapperClasses.get(type); + static { + wrapperClasses.put(boolean.class, Boolean.class); + wrapperClasses.put(short.class, Short.class); + wrapperClasses.put(int.class, Integer.class); + wrapperClasses.put(Long.Type, Long.class); // we can do it this way! + wrapperClasses.put(float.class, Float.class); + wrapperClasses.put(double.class, Double.class); + } + * The alternative is to register PParsers with corresponding Primitive type too. + * + * Also canHandle() could use + return wrapperClasses.keySet().contains(type) || wrapperClasses.entrySet().contains(type); + + * 2. Parsing can be implemented via reflection + return type.getMethod("valueOf", new Class[]{String.class}).invoke(null, string); + + * I don't like using reflection as it prevents optimisation, + * also now Strings and Characters are handled in a nice fashion. + * + * As for convertToPrimitive trick both ways are good, + * but current looks more generic though tricky + */ + +//// some test, should it be commented out? +// public static void main(String[] args) +// { +// try +// { +// String str = "0"; +// Object o = null; +// str = "0"; +// o = parse(str, String.class); +// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +// +// str = "0"; +// o = parse(str, int.class); +// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +// str = "0"; +// o = parse(str, Integer.class); +// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +// +// str = "0,1,2"; +// o = parse(str, int[].class); +// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + (int[]) o + "#"); +// System.out.println("DATA:" + java.util.Arrays.toString((int[])o)); +// // System.out.println("DATA:" + java.util.Arrays.deepToString( (int[]) o)); +// +// str = "0"; +// o = parse(str, byte.class); +// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +// +// str = "0"; +// o = parse(str, HashMap.class); +// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +//// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +// } catch (ParserException ex) +// { +// System.out.println("" +ex); +// } +//// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#"); +// +// } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/package-info.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/package-info.java new file mode 100644 index 00000000000..9db8f2c10a8 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/package-info.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/** + * This framework allows one to automate parsing of the test command line + * arguments (it automatically sets the corresponding fields of the + * test class). +

      +

      A simplified example

      +Suppose we want to to define a test Test with an option "iterations", +which can be run via +

      +
       > java Test -iterations 10 
      +or via +
       java Test 
      +in the last case iterations defaults to 100. +

      +We want to achieve this by annotating fields of the Test class by +a special @Option annotation. +

      +For simplicity suppose @Option is defined as follows: +

      + @interface Option
      + { //here all the annotation fields are mandatory
      +        String name();
      +        String default();
      +        String description();
      + }
      + 
      + The test class uses an API like: +
      +     public class OptionSupport {
      +     public static void setup(Object test, String[] args);
      + }
      +
      +Now a simple example: +
      +public class Test {
      +
      +    @Option( name="iterations",
      +                 default="100",
      +                 description="Number of iterations")
      +    int iterations;
      +    public void run() {
      +        // ..do actual testing here..
      +    }
      +
      +    public static void main(String args) {
      +        Test test = new Test();
      +        OptionsSupport.setup(test, args); // instead of manually
      +                      // parsing arguments
      +        // now test.iterations is set to 10 or 100.
      +        test.run();
      +    }
      +}
      +
      +This test can be also run via +
      +- java Test -help
      +
      +Then OptionSupport.setup() shows +help and exits (by throwing exception?): +
      +   Supported options:
      +    -iterations 
      +              Number of iterations (mandatory)
      +
      +We also want to be able to apply this to fields of non-simple types (via +factories) and to other classes recursively (see @Options annotation +below). +

      +Please, see {@link vm.share.options.test.SimpleExample} +for a working version of this. + *

      General description

      + Options are defined using annotations like this: +
      +public class StressOptions {
      +    // [2]
      +    @Option(name="stressTime",
      +                default_value="60",
      +                description="Stress time")
      +    private long stressTime;
      +
      +    ...
      +}
      +
      +

      we want to use command line like +

       java Test -stressTime 50 
      +here 50 is passed to the StressOptions.stressTime field. +see {@link vm.share.options.Options} below.

      +
      +public class Test {
      +    // [1]
      +    @Options
      +    StressOptions stressOptions = new StressOptions();
      +
      +    // [2]
      +    @Option(name="iterations",
      +                default_value="100",
      +                description="Number of iterations")
      +    int iterations;
      +
      +    // [3]
      +    @Option(
      +        name="garbageProducer",
      +        default="byteArr",
      +        description="Garbage  producer",
      +        factory="nsk.share.gc.gp.GarbageProducerFactory")
      +    GarbageProducer garbageProducer;
      +...
      +
      +    // [4]
      +    @Option(name="logger",
      +         description="Logger",
      +     factory="nsk.share.log.LogFactory")
      +    Log log;
      +
      +    public void run() {
      +        log.info("Start test");
      +        log.info("Finish test");
      +    }
      +
      +    public static void main(String[] args) {
      +        Test test = new Test();
      +        OptionsSupport.setup(test, args);
      +        test.run();
      +    }
      +}
      +
      +

      The API is invoked via a call to {@link vm.share.options.OptionSupport#setup(Object, String[])}). + Also there is {@link vm.share.options.OptionSupport#setup(Object, String[], OptionHandler)}) method. + It allows the caller to pass a handler which takes + care of the options not defined via @Option annotation. +

      + +

      Requirements

      +

      + - The following field types are supported out-of-box: [2] +

        +
      • All basic (primitive) types (int, long, ...) and corresponding wrapper types. +
      • In the case of a boolean type option user is allowed to skip second argument, + i.e. write '-option_name' + instead of '-option_name true'. +
      • Strings. +
      • One dimentional arrays of the above (comma-separated). +
      • Classes if a factory is specified, see below. + NOTE: currently there is no way to pass some options to the instantiated objects. +
      +

      +

      All non-static fields (including private and protected) of class and + it's superclasses are scanned for annotations. +

      +

      + (Possibly) Same annotations for setter methods ? (NOT IMPLEMENTED) +

      +

      + It is possible to inherit options of the field type + through @Options annotations, see {@link vm.share.options.Options}, and [1] above. +

      +

      + Option.name defaults to the name of the field. +

      +

      Object options are supported using {@link vm.share.options.OptionObjectFactory}, see [3] above. +Please see {@link vm.share.options.OptionObjectFactory} interface, it should be +implemented by the user and specified in the Option.factory attribute. +

      +

      +As a shortcut we provide BasicOptionObjectFactory class, which allows user to +create a factory via @{@link vm.share.options.Factory} annotation: +

      +@Factory (
      +    placeholder_text="garbage producer", //used for generating <..> in the help message
      +    default_value="byteArr",
      +    classlist={
      +        @FClass(key="byteArr",
      +                     type="nsk.share.gc.gp.array.ByteArrayProducer",
      +                     description="byte array producer")
      +        @FClass(key="charArr",
      +                     type="nsk.share.gc.gp.array.CharArrayProducer",
      +                     description="char array producer")
      +        ...
      +    }
      +)
      +public class GarbageProducerFactory extends BasicOptionObjectFactory {
      +}
      +
      +

      note: for subclasses of BasicOptionObjectFactory +factories can extend each other!! +so the check for @OptionObjectFactory is done recursively. +NOT SURE IF THIS IS IMPLEMENTED. +

      +

      If there is no unknownOptionHandler then in case of unsupported +option, a Runtime exception is thrown. +

      +

      + If there is no 'default' annotation attribute and there is no default +for OptionObjectFactory, then option is mandatory and a Runtime exception is thrown if +it's missing. +

      +

      Both '-option value' and '-option=value' formats are supported. +

      +

      If main class is given '-help', OptionSupport.setup() shows +help and exits (by throwing a Runtime exception): +

      +Supported options:
      +    -iterations 
      +              Number of iterations (mandatory)
      +        -stressTime 
      +              Stress time (default 60)
      +    -garbageProducer 
      +              Garbage producer (default byteArr). Supported keys:
      +                  byteArr    byte array producer
      +                  charArr    char array producer
      +                  ...
      +        ...
      +
      + +

      NOT IMPLEMENTED: +Integer type boundaries are validated with RuntimeException with detailed +meaningful error message. Other validations that are possible are also done. +

      +

      NOT IMPLEMENTED: + Empty default ("") value for Object annotations [3] means null value. +

      +

      The object created via factory is also scanned for @Option annotations +(like in the @Options case), i.e. it inherits options from the Test class. + This is not implemented as it causes several problems, in particular, the +object must be instanciated in order to be scanned for options, hence no meaningful +help message could be generated for corresponding options. +One of the possible solutions +is to allow -object_opt_name.suboption syntax (or even with a colon), and to pass the +corresponding suboptions Map to the OptionObjectFactory, it could use OptionFramework +to take care of it. It is unclear, what other problems can arise. +

      + * + */ +package vm.share.options; diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/test/BasicObjectFactoryUsageExample.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/BasicObjectFactoryUsageExample.java new file mode 100644 index 00000000000..eeb2e646bef --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/BasicObjectFactoryUsageExample.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package vm.share.options.test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import vm.share.options.BasicOptionObjectFactory; +import vm.share.options.FClass; +import vm.share.options.Factory; + +/** + * This is a simple example of BasicObjectFactory utility class, + * which allows us to produce {@link vm.share.options.ObjectFactory} + * implementations via annotations. + * @see vm.share.options.ObjectFactory + * @see vm.share.options.BasicObjectFactory + * @see vm.share.options.Factory + * @see vm.share.options.FClass + */ +@Factory(description="dummy factory", default_value="array_list", placeholder_text="a type", +classlist={ +@FClass(description="a linked list", key="linked_list", type=LinkedList.class), +@FClass(description="an array list", key="array_list", type=ArrayList.class) +}) + // MUST BE PUBLIC or it could not be istantiated!! +public class BasicObjectFactoryUsageExample extends BasicOptionObjectFactory +{ + + + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/test/ExampleWithNonprimitiveOptions.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/ExampleWithNonprimitiveOptions.java new file mode 100644 index 00000000000..91cf2d74693 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/ExampleWithNonprimitiveOptions.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package vm.share.options.test; + +import java.util.Collection; +import vm.share.options.Option; +import vm.share.options.OptionSupport; + +/** + * This example uses @Option annotation with an a factory attribute, + * to populate a field of a non-simple type. + */ +public class ExampleWithNonprimitiveOptions +{ + + @Option(name = "iterations", default_value = "100", description = "Number of iterations") + int iterations; + + + @Option(description = "quiet or verbose") + private String running_mode; + + @Option(description = "type of the list", + factory=vm.share.options.test.BasicObjectFactoryUsageExample.class) + private Collection list; + + public void run() + { + // ..do actual testing here.. + System.out.println("iterations = " + iterations); + System.out.println("RM : " + running_mode); + System.out.println("list is " + list.getClass()); + } + + + public static void main(String[] args) + { + ExampleWithNonprimitiveOptions test = new ExampleWithNonprimitiveOptions(); + OptionSupport.setup(test, args); // instead of manually // parsing arguments + // now test.iterations is set to 10 or 100. + test.run(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExample.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExample.java new file mode 100644 index 00000000000..16646854845 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExample.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * This is a very simple test for our framework. + */ +package vm.share.options.test; + +import vm.share.options.Option; +import vm.share.options.OptionSupport; + +/** + * This is a very simple usage example of the framework + * @see vm.share.options.Option + * @see vm.share.options.OptionSupport + */ +public class SimpleExample +{ + + @Option(name = "iterations", default_value = "100", description = "Number of iterations") + int iterations; + + + @Option(description = "quiet or verbose") + private String running_mode; + + public void run() + { + // ..do actual testing here.. + System.out.println("iterations = " + iterations); + System.out.println("RM : " + running_mode); + } + + + public static void main(String[] args) + { + SimpleExample test = new SimpleExample(); + OptionSupport.setup(test, args); // instead of manually + // parsing arguments + // now test.iterations is set to 10 or 100 (default value). + test.run(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExampleWithOptionsAnnotation.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExampleWithOptionsAnnotation.java new file mode 100644 index 00000000000..7814beb5192 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExampleWithOptionsAnnotation.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package vm.share.options.test; + +import vm.share.options.Option; +import vm.share.options.OptionSupport; +import vm.share.options.Options; + + +/** + * This is again a simple example which shows the power of @Options annotation. + * @see vm.share.options.Options + * @see vm.share.options.Option + * @see vm.share.options.OptionSupport + */ + +public class SimpleExampleWithOptionsAnnotation +{ + @Options + StressOptions stressOptions = new StressOptions(); + @Option(name = "iterations", default_value = "100", description = "Number of iterations") + int iterations; + + @Option(description = "quiet or verbose") + String running_mode; + + public void run() + { + // ..do actual testing here.. + System.out.println("iterations = " + iterations); + System.out.println("RM: " + running_mode); + System.out.println("StressOptions " + stressOptions.getStressTime()); + } + + + public static void main(String[] args) + { + SimpleExampleWithOptionsAnnotation test = new SimpleExampleWithOptionsAnnotation(); + OptionSupport.setup(test, args); // instead of manually // parsing arguments + // now test.iterations is set to 10 or 100. + test.run(); + } +} + +class StressOptions +{ + @Option(default_value="60", description="Stress time") + private long stressTime; + + public long getStressTime() + { + return stressTime; + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SubClassExample.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SubClassExample.java new file mode 100644 index 00000000000..3aa8cd91ede --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SubClassExample.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * This is a very simple test for our framework. + */ +package vm.share.options.test; + +import vm.share.options.Option; +import vm.share.options.OptionSupport; + +/** + * This is an example with annotated superclasses + * @see vm.share.options.Option + * @see vm.share.options.OptionSupport + */ +public class SubClassExample extends SimpleExampleWithOptionsAnnotation +{ + + @Option(name = "timeout", default_value = "100", description = "timeout") + int timeout; + + + @Option(name = "logging_mode", description = "quiet or verbose") + private String logging_mode; + + @Override + public void run() + { + // ..do actual testing here.. + System.out.println("iterations = " + iterations); + System.out.println("RM : " + running_mode); + System.out.println("logging_mode" + logging_mode); + System.out.println("timeout " + timeout); + System.out.println("stresstime " + stressOptions.getStressTime()); + } + + + public static void main(String[] args) + { + SubClassExample test = new SubClassExample(); + OptionSupport.setup(test, args); // instead of manually + // parsing arguments + // now test.iterations is set to 10 or 100 (default value). + test.run(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/options/test/package-info.java b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/package-info.java new file mode 100644 index 00000000000..fa4cf1a10be --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + + */ +/** + * This package contains a number of short examples which demonstrate + * the most typical usage use this API, please, take a look at the source code. + */ +package vm.share.options.test; diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/CmdExecutor.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/CmdExecutor.java new file mode 100644 index 00000000000..bea1bd8282b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/CmdExecutor.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import java.io.IOException; +import java.util.Collection; + +public class CmdExecutor extends ProcessExecutor { + private final StringBuilder cmd = new StringBuilder(); + @Override + public void clearArgs() { + cmd.setLength(0); + } + + @Override + public void addArg(String arg) { + cmd.append(" " + arg); + } + + @Override + public void addArgs(String[] args) { + for (String arg : args) { + addArg(arg); + } + } + + @Override + public void addArgs(Collection args) { + for (String arg : args) { + addArg(arg); + } + } + + @Override + protected Process createProcess() throws IOException { + return Runtime.getRuntime().exec(cmd.toString()); + } + + @Override + public String toString() { + return cmd.toString(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageInput.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageInput.java new file mode 100644 index 00000000000..d684d88f543 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageInput.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import java.util.List; + +public interface MessageInput { + public boolean waitForStart(long timeout) throws InterruptedException; + public boolean waitForMessage(long timeout) throws InterruptedException; + public boolean waitForMessage(String msg, long timeout) throws InterruptedException; + public String getMessage(); + public List getMessages(); + public List getMessages(int to); + public List getMessages(int from, int to); + public boolean waitForFinish(long timeout) throws InterruptedException; + public void reset(); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageOutput.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageOutput.java new file mode 100644 index 00000000000..3a0b4549c48 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageOutput.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +public interface MessageOutput { + public void start(); + public void send(String msg); + public void finish(); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessExecutor.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessExecutor.java new file mode 100644 index 00000000000..0d9a0e06329 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessExecutor.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import nsk.share.TestBug; +import nsk.share.TestFailure; +import nsk.share.log.Log; +import vm.share.ProcessUtils; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.IOException; +import java.util.*; +import java.lang.reflect.Field; + +public class ProcessExecutor { + private static long CLEANUP_TIMEOUT = 60000; + private Process process; + private StreamReader stdoutReader = new StreamReader("stdout"); + private StreamReader stderrReader = new StreamReader("stderr"); + private Waiter waiter = new Waiter(); + private OutputStream stdin; + private volatile boolean running; + private volatile int result = -1; + private List args = new ArrayList(); + + public int getResult() { + return result; + } + + public void clearArgs() { + this.args.clear(); + } + + public void addArg(String arg) { + this.args.add(arg); + } + + public void addArgs(String[] args) { + for (String arg : args) { + this.args.add(arg); + } + } + + public void addArgs(Collection args) { + this.args.addAll(args); + } + + private void printCommandLine() { + for (String arg : args) { + System.out.println(arg); + } + } + + /* + * Start process. + */ + public void start() { + if (process != null) { + throw new TestBug("Process is already started"); + } + printCommandLine(); + try { + process = createProcess(); + stdoutReader.setDescription("stdout: " + toString()); + stdoutReader.setStream(process.getInputStream()); + stderrReader.setDescription("stderr: " + toString()); + stderrReader.setStream(process.getErrorStream()); + stdin = process.getOutputStream(); + stdoutReader.start(); + stderrReader.start(); + waiter.start(); + } catch (IOException e) { + throw new TestFailure("Error running process: " + toString(), e); + } + } + + protected Process createProcess() throws IOException { + String[] commandLine = args.toArray(new String[args.size()]); + return Runtime.getRuntime().exec(commandLine); + } + + /** + * Run and wait for completion. + */ + public int execute(long timeout) { + if (timeout <= 0) { + throw new TestBug("Positive timeout is required"); + } + start(); + return waitFor(timeout); + } + + public int waitFor(long timeout) { + if (process == null) { + throw new TestBug("Process is not yet started"); + } + if (timeout <= 0) { + throw new TestBug("Positive timeout is required"); + } + long timeleft = timeout; + long startTime = 0; + while (timeleft > 0) { + try { + startTime = System.currentTimeMillis(); + waiter.join(timeout); + return result; + } catch (InterruptedException e) { + e.printStackTrace(); + } + timeleft -= (System.currentTimeMillis() - startTime); + } + return -1; + } + + public int getPid() { + return ProcessUtils.getPid(process); + } + + public OutputStream getStdIn() { + if (process == null) { + throw new TestBug( + "Process is not running; prepare writers after it is started"); + } + return stdin; + } + + public PrintStream getStdInPrint() { + return new PrintStream(getStdIn(), + true); // Autoflush is important here. + } + +/* + public InputStream getStdOut() { + if (process != null) + throw new TestBug("Process is already running; prepare readers before it is started or some output may be missed"); + return stdoutReader.getInputStream(); + } + + public BufferedReader getStdOutReader() { + return new BufferedReader(new InputStreamReader(getStdOut())); + } + + public InputStream getStdErr() { + if (process != null) + throw new TestBug("Process is already running; prepare readers before it is started or some output may be missed"); + return stderrReader.getInputStream(); + } + + public BufferedReader getStdErrReader() { + return new BufferedReader(new InputStreamReader(getStdOut())); + } + + public String getStdoutOutput() { + if (stdoutReader == null) + throw new TestBug("Process is not running"); + return stdoutReader.getOutput(); + } + + public String getStderrOutput() { + if (stderrReader == null) + throw new TestBug("Process is not running"); + return stderrReader.getOutput(); + } + */ + + public void addStdOutListener(StreamListener l) { + stdoutReader.addListener(l); + } + + public void addStdErrListener(StreamListener l) { + stderrReader.addListener(l); + } + + public void logStdOut(String prefix, Log log) { + stdoutReader.addListener(new StreamLogger(prefix, log)); + } + + public void logStdErr(String prefix, Log log) { + stderrReader.addListener(new StreamLogger(prefix, log)); + } + + public void logStdOutErr(String prefix, Log log) { + logStdOut(prefix, log); + logStdErr("(stderr)" + prefix, log); + } + + public boolean isStarted() { + return (process != null); + } + + public void kill() { + if (process == null) { + throw new TestBug("Process is not running"); + } + process.destroy(); + if (stdoutReader != null) { + stdoutReader.kill(); + } + if (stderrReader != null) { + stderrReader.kill(); + } + if (waiter != null && waiter.isAlive()) { + waiter.kill(); + } + process = null; + } + + public void finish() { + if (stdoutReader != null) { + try { + stdoutReader.join(CLEANUP_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + stdoutReader = null; + } + if (stderrReader != null) { + try { + stderrReader.join(CLEANUP_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + stderrReader = null; + } + process = null; + } + + public String toString() { + String ts = ""; + if (args != null) { + for (String s : args) { + ts += s; + ts += " "; + } + } + return ts; + } + + private class Waiter extends Thread { + public Waiter() { + super("Process Waiter: (not setup)"); + setDaemon(true); + } + + public void run() { + setName("Process Waiter: " + ProcessExecutor.this); + try { + result = process.waitFor(); + } catch (InterruptedException e) { + // Ignore + } + } + + public void kill() { + this.interrupt(); + long timeleft = CLEANUP_TIMEOUT; + long startTime = 0; + while (timeleft > 0) { + try { + startTime = System.currentTimeMillis(); + this.join(timeleft); + return; + } catch (InterruptedException e) { + e.printStackTrace(); + } + timeleft -= (System.currentTimeMillis() - startTime); + } + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessHandler.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessHandler.java new file mode 100644 index 00000000000..4ca3b191993 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessHandler.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import java.util.List; + +public class ProcessHandler implements MessageInput, MessageOutput { + private StreamMessageInput stdout = new StreamMessageInput(); + private StreamMessageInput stderr = new StreamMessageInput(); + private StreamMessageOutput stdin = new StreamMessageOutput(); + + public ProcessHandler() { + } + + public ProcessHandler(ProcessExecutor exec) { + bind(exec); + } + + public void bind(ProcessExecutor exec) { + exec.addStdOutListener(stdout.createListener()); + exec.addStdErrListener(stderr.createListener()); + exec.start(); + stdin.bind(exec.getStdIn()); + } + + public boolean waitForStart(long timeout) throws InterruptedException { + return stdout.waitForStart(timeout) && stderr.waitForStart(timeout); + } + + public boolean waitForMessage(long timeout) throws InterruptedException { + return stdout.waitForMessage(timeout); + } + + public boolean waitForMessage(String msg, long timeout) throws InterruptedException { + return stdout.waitForMessage(msg, timeout); + } + + public String getMessage() { + return stdout.getMessage(); + } + + public List getMessages() { + return stdout.getMessages(); + } + + public List getMessages(int to) { + return stdout.getMessages(to); + } + + public List getMessages(int from, int to) { + return stdout.getMessages(from, to); + } + + public boolean waitForStdErrMessage(String msg, long timeout) throws InterruptedException { + return stderr.waitForMessage(msg, timeout); + } + + public String getStdErrMessage() { + return stderr.getMessage(); + } + + public boolean waitForFinish(long timeout) throws InterruptedException { + return stdout.waitForFinish(timeout) && stderr.waitForFinish(timeout); + } + + public void start() { + stdin.start(); + } + + public void send(String msg) { + stdin.send(msg); + } + + public void finish() { + stdin.finish(); + } + + public void reset() { + stdout.reset(); + stderr.reset(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamListener.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamListener.java new file mode 100644 index 00000000000..26c542f9bd0 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamListener.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +/* + * StreamListener listens on events from BufferedInputStream. + * + * Note: StreamListener should not never block as it potentially + * runs in thread that reads the input. + */ +public interface StreamListener { + public void onStart(); + public void onRead(String line); + public void onFinish(); + public void onException(Throwable e); +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamLogger.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamLogger.java new file mode 100644 index 00000000000..5162e4010ff --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamLogger.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import nsk.share.log.Log; + +/* + * StreamListener that logs everything to Log at debug priority. + */ +public class StreamLogger implements StreamListener { + private String prefix; + private Log log; + + public StreamLogger(String prefix, Log log) { + this.prefix = prefix; + this.log = log; + } + + public void onStart() { + // do nothing + } + + public void onFinish() { + // do nothing + } + + public void onRead(String s) { + log.debug(prefix + s); + } + + public void onException(Throwable e) { + log.debug(prefix + "Exception"); + log.debug(e); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageInput.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageInput.java new file mode 100644 index 00000000000..03d9ec6bd3e --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageInput.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import java.util.List; +import java.util.ArrayList; +import nsk.share.TestBug; + +public class StreamMessageInput implements MessageInput { + private Object sync = new Object(); + private List lines = new ArrayList(); + private int position = 0; + private volatile boolean active = false; + private volatile Throwable exception; + + public StreamMessageInput() { + } + + public StreamMessageInput(StreamReader sd) { + bind(sd); + } + + public StreamListener createListener() { + return new Listener(); + } + + public void bind(StreamReader sd) { + sd.addListener(createListener()); + } + + public boolean isActive() { + return active; + } + + public boolean isException() { + return exception != null; + } + + public Throwable getException() { + return exception; + } + + public boolean waitForStart(long timeout) throws InterruptedException { + long startTime = System.currentTimeMillis(); + long curTime = startTime; + synchronized (sync) { + while (!active && curTime - startTime < timeout) { + sync.wait(curTime - startTime); + curTime = System.currentTimeMillis(); + } + } + return active; + } + + public boolean waitForFinish(long timeout) throws InterruptedException { + long startTime = System.currentTimeMillis(); + long curTime = startTime; + synchronized (sync) { + while (active && curTime - startTime < timeout) { + sync.wait(curTime - startTime); + curTime = System.currentTimeMillis(); + } + } + return !active; + } + + public boolean waitForMessage(String msg, long timeout) throws InterruptedException { + long startTime = System.currentTimeMillis(); + long curTime = startTime; + int n = position; + synchronized (sync) { + while (curTime - startTime < timeout) { + while (n < lines.size()) { + // System.out.println("Check: " + lines.get(n)); + if (msg == null || lines.get(n++).contains(msg)) { + return true; + } + } + sync.wait(timeout - (curTime - startTime)); + curTime = System.currentTimeMillis(); + } + return false; + } + } + + public boolean waitForMessage(long timeout) throws InterruptedException { + return waitForMessage(null, timeout); + } + + public String getMessage() { + if (position < lines.size()) + return lines.get(position++); + else + return null; + } + + public String getMessage(int index) { + return lines.get(index); + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public int getMessageCount() { + return lines.size(); + } + + public List getMessages() { + return getMessages(position, lines.size()); + } + + public List getMessages(int to) { + return getMessages(position, to); + } + + public List getMessages(int from, int to) { + synchronized (sync) { + if (to < 0) + to = lines.size() + to; + position = Math.max(position, to); + return new ArrayList(lines.subList(from, to)); + } + } + + public void reset() { + synchronized (sync) { + position = lines.size(); + } + } + + private class Listener implements StreamListener { + @Override + public void onStart() { + synchronized (sync) { + active = true; + sync.notifyAll(); + } + } + + @Override + public void onRead(String line) { + //System.out.println("onRead: " + line); + synchronized (sync) { + lines.add(line); + sync.notifyAll(); + } + } + + @Override + public void onFinish() { + synchronized (sync) { + active = false; + sync.notifyAll(); + } + } + + @Override + public void onException(Throwable e) { + exception = e; + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageOutput.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageOutput.java new file mode 100644 index 00000000000..473ccc071f9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageOutput.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.IOException; +import nsk.share.TestFailure; + +public class StreamMessageOutput implements MessageOutput { + private OutputStream out; + private PrintStream pout; + + public StreamMessageOutput() { + } + + public StreamMessageOutput(OutputStream out) { + bind(out); + } + + public void bind(OutputStream out) { + this.out = out; + this.pout = new PrintStream(out, true); // Autoflush is important + } + + public void start() { + } + + public void send(String msg) { + pout.println(msg); + } + + public void finish() { + pout.close(); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamReader.java b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamReader.java new file mode 100644 index 00000000000..a8f56318da5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamReader.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.process; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; +import java.util.ArrayList; + +public class StreamReader extends Thread { + private InputStream in; + private List listeners; + private volatile boolean terminate = false; + private static final long CLEANUP_TIMEOUT = 60000; + + public StreamReader(String desc) { + super("Stream Reader: " + desc); + setDaemon(true); + } + + public StreamReader(String desc, InputStream in) { + this(desc); + setStream(in); + } + + public void setDescription(String desc) { + setName("Stream Reader: " + desc); + } + + public void setStream(InputStream in) { + this.in = in; + } + + public synchronized void addListener(StreamListener listener) { + if (listeners == null) + listeners = new ArrayList(); + listeners.add(listener); + } + + public synchronized void removeListener(StreamListener listener) { + if (listeners != null) { + while (listeners.remove(listener)) + ; + } + } + + public void run() { + onStart(); + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(in)); + String line; + while (!terminate) { + line = rd.readLine(); + if (line == null) + break; + onRead(line); + while (rd.ready()) { + line = rd.readLine(); + if (line == null) + break; + onRead(line); + } + if (line == null) + break; + } + cleanup(); + onFinish(); + } catch (IOException e) { + if (!terminate) + onException(e); + else + onFinish(); + } + } + + protected void onStart() { + if (listeners != null) { + for (StreamListener l : listeners) + l.onStart(); + } + } + + protected void onRead(String line) { + //System.out.println("Read: " + line); + if (listeners != null) { + for (StreamListener l : listeners) + l.onRead(line); + } + } + + protected void onFinish() { + if (listeners != null) { + for (StreamListener l : listeners) + l.onFinish(); + } + } + + protected void onException(Throwable e) { + if (listeners != null) { + for (StreamListener l : listeners) + l.onException(e); + } + } + + private void cleanup() { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void kill() { + terminate = true; + try { + this.join(CLEANUP_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + this.interrupt(); + try { + this.join(CLEANUP_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/stack/StackUtils.java b/test/hotspot/jtreg/vmTestbase/vm/share/stack/StackUtils.java new file mode 100644 index 00000000000..a55ad545503 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/stack/StackUtils.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.stack; + +import java.util.List; +import java.util.Map; + +import nsk.share.TestFailure; +import nsk.share.log.Log; + +public final class StackUtils { + private StackUtils() { + } + + private static String replace(String s) { + return (s == null || s.length() == 0) ? "?" : s; + } + + /** + * String representation of stack trace element. + * + * Note that null and empty values are replaced with '?'. + */ + public static String strStackTraceElement(StackTraceElement element) { + return "at " + replace(element.getClassName()) + "." + replace(element.getMethodName()) + "(" + replace(element.getFileName()) + ":" + element.getLineNumber() + ")"; + } + + public static void printStackTraceElement(Log log, StackTraceElement element) { + log.info(" " + strStackTraceElement(element)); + } + + public static void printStackTrace(Log log, StackTraceElement[] elements) { + for (StackTraceElement element : elements) + printStackTraceElement(log, element); + } + + public static void printStackTrace(Log log, Iterable elements) { + for (StackTraceElement element : elements) + printStackTraceElement(log, element); + } + + /** + * Check that element matches expected element. + * + * Expected element is used as pattern for matching. A null or empty + * field value means that no comparison is done. + */ + public static boolean matches(StackTraceElement element, StackTraceElement expected) { + return + (expected.getClassName() == null || expected.getClassName().length() == 0 || expected.getClassName().equals(element.getClassName())) && + (expected.getMethodName() == null || expected.getMethodName().length() == 0 || expected.getMethodName().equals(element.getMethodName())) && + (expected.isNativeMethod() == element.isNativeMethod()); + } + + public static StackTraceElement expectedTraceElement(String className, String methodName, boolean nativeMethod) { + // Replace null className with empty because StackTraceElement constructor does not allow null className. + return new StackTraceElement(className == null ? "" : className, methodName, null, (nativeMethod ? -2 : 0)); + } + + public static void addExpectedTraceElement(List expectedTrace, String className, String methodName, boolean nativeMethod) { + expectedTrace.add(0, expectedTraceElement(className, methodName, nativeMethod)); + } + + /** + * Check that trace elements starting from given index match expected elements. + */ + public static void checkMatches(StackTraceElement[] elements, List expectedTrace, int i) { + if (elements.length - i < expectedTrace.size()) + throw new TestFailure("Expected at least " + expectedTrace.size() + " trace elements, got only " + (i + 1)); + for (int j = 0; j < expectedTrace.size(); ++j) { + StackTraceElement expected = expectedTrace.get((expectedTrace.size() - 1) - j); + int index = (elements.length - 1) - i - j; + StackTraceElement actual = elements[index]; + if (!matches(actual, expected)) + throw new TestFailure("Expected element at index " + index + " to match: " + strStackTraceElement(expected)); + } + } + + /** + * Find matching stack trace element starting from top of the stack. + */ + public static int findMatch(StackTraceElement[] elements, StackTraceElement expected) { + for (int i = 0; i < elements.length; ++i) + if (StackUtils.matches(elements[elements.length - 1 - i], expected)) + return i; + return -1; + } + + /** + * Find the stack trace element that contains the "main(String[])" method + * + * @return StackTraceElement containing "main" function, null if there are more than one + */ + public static StackTraceElement findMain() { + Map stackTraces = Thread.getAllStackTraces(); + StackTraceElement mainMethodFrame = null; + for(StackTraceElement[] current : stackTraces.values()) { + if (current.length > 0) { + StackTraceElement last = current[current.length - 1]; + if ("main".equals(last.getMethodName())) { + if (mainMethodFrame == null) { + mainMethodFrame = last; + } else if (!mainMethodFrame.getClassName().equals(last.getClassName())) { + // more than one class has a "main" + return null; + } + } + } + } + return mainMethodFrame; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/transform/AbstractClassFileTransformer.java b/test/hotspot/jtreg/vmTestbase/vm/share/transform/AbstractClassFileTransformer.java new file mode 100644 index 00000000000..95906789fda --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/transform/AbstractClassFileTransformer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.transform; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; + +public abstract class AbstractClassFileTransformer + implements ClassFileTransformer { + protected abstract boolean shouldBeTransformed(String name); + + protected abstract byte[] transformClass(byte[] bytes); + + @Override + public byte[] transform(ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) throws IllegalClassFormatException { + if (shouldBeTransformed(className)) { + return transformClass(classfileBuffer); + } + return null; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/transform/AnnotationAppender.java b/test/hotspot/jtreg/vmTestbase/vm/share/transform/AnnotationAppender.java new file mode 100644 index 00000000000..b3891fec5e4 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/transform/AnnotationAppender.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.transform; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; + +public abstract class AnnotationAppender { + private final String desc; + private final boolean visible; + private boolean annotationPresent; + + public AnnotationAppender(String desc, boolean visible) { + this.desc = desc; + this.visible = visible; + } + + public void checkAnnotation(String desc, boolean isVisible) { + annotationPresent |= visible == isVisible && this.desc.equals(desc); + } + + public void addAnnotation(VisitAnnotation func) { + if (shouldAdd()) { + AnnotationVisitor av = func.visit(desc, true); + if (av != null) { + postCreate(av); + av.visitEnd(); + annotationPresent = true; + } + } + } + + protected boolean shouldAdd() { + return !annotationPresent; + } + + protected abstract void postCreate(AnnotationVisitor av); + + @FunctionalInterface + public static interface VisitAnnotation { + AnnotationVisitor visit(String desc, boolean visible); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/transform/TransformingClassLoader.java b/test/hotspot/jtreg/vmTestbase/vm/share/transform/TransformingClassLoader.java new file mode 100644 index 00000000000..5ce3dd02eb6 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/transform/TransformingClassLoader.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.transform; + +import vm.share.FileUtils; + +public class TransformingClassLoader extends ClassLoader { + private final AbstractClassFileTransformer transformer; + + protected TransformingClassLoader(ClassLoader parent, + AbstractClassFileTransformer transformer) { + super(parent); + this.transformer = transformer; + } + + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + if (!transformer.shouldBeTransformed(name)) { + return super.loadClass(name, resolve); + } + synchronized (getClassLoadingLock(name)) { + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + if (c == null) { + try { + byte[] bytes = FileUtils.readClass(name); + bytes = transformer.transformClass(bytes); + c = defineClass(name, bytes, 0, bytes.length); + } catch (Exception e) { + e.printStackTrace(); + return super.loadClass(name, resolve); + } + } + if (resolve) { + resolveClass(c); + } + return c; + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/Crasher.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/Crasher.java new file mode 100644 index 00000000000..4d16a842416 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/Crasher.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmcrasher; + +public abstract class Crasher implements Runnable { + + public abstract void run(); + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/CrasherFactory.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/CrasherFactory.java new file mode 100644 index 00000000000..37e207ace06 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/CrasherFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmcrasher; + +import vm.share.options.BasicOptionObjectFactory; +import vm.share.options.FClass; +import vm.share.options.Factory; + +@Factory(placeholder_text="Crasher type", default_value="signal", classlist={ + @FClass(key="signal", description="Crash VM with a signal", type=SignalCrasher.class), + @FClass(key="unsafe.gc", description="Crash VM in GC with Unsafe interface", type=UnsafeGCCrasher.class), + @FClass(key="unsafe.java", description="Crash VM in Java thread with Unsafe interface", type=UnsafeJavaCrasher.class), +}) +public class CrasherFactory extends BasicOptionObjectFactory { +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/SignalCrasher.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/SignalCrasher.java new file mode 100644 index 00000000000..df18bfd6df9 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/SignalCrasher.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmcrasher; + +import vm.share.ProcessUtils; +import vm.share.options.Option; + +public class SignalCrasher extends Crasher { + @Option(name="signalnum", description="signal number", default_value="2") + private int num; + + public void run() { + ProcessUtils.sendSignal(num); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeGCCrasher.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeGCCrasher.java new file mode 100644 index 00000000000..772b971bf63 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeGCCrasher.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmcrasher; + +import vm.share.UnsafeAccess; + +public class UnsafeGCCrasher extends Crasher { + + private static class C { + C next; + } + + private static C a = null; + + @SuppressWarnings("restriction") + @Override + public void run() { + try { + a = new C(); + a.next = new C(); + a.next.next = new C(); + a.next.next.next = new C(); + UnsafeAccess.unsafe.putInt(a.next, UnsafeAccess.unsafe.objectFieldOffset(C.class.getDeclaredField("next")), 0xDEADCAFE); + System.gc(); + Thread.sleep(1000); + } catch ( Throwable t ) { + t.printStackTrace(); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeJavaCrasher.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeJavaCrasher.java new file mode 100644 index 00000000000..49069e435a5 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeJavaCrasher.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmcrasher; + +import vm.share.UnsafeAccess; + +public class UnsafeJavaCrasher extends Crasher { + + private static class C { + C next; + } + + @SuppressWarnings("restriction") + @Override + public void run() { + try { + C a = new C(); + a.next = new C(); + a.next.next = new C(); + UnsafeAccess.unsafe.putInt(a.next, UnsafeAccess.unsafe.objectFieldOffset(C.class.getDeclaredField("next")), 0xDEADCAFE); + a.next.next.next = new C(); + } catch ( Throwable t ) { + t.printStackTrace(); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/CompileAndDeoptimize.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/CompileAndDeoptimize.java new file mode 100644 index 00000000000..bf384a3338a --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/CompileAndDeoptimize.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmstresser; + +public class CompileAndDeoptimize implements Runnable { + + public static int v = 0; + + private abstract static class A { + public abstract void incv(); + } + + private static class B extends A { + public void incv() { + v++; + } + } + + public static class C extends A { + public void incv() { + v += (new int[1][1][1][1][1][1][1][1]).length; + } + } + + private volatile boolean done = false; + public volatile A a = new B(); + + private void incv() { + a.incv(); + } + + private void inc() { + while ( ! done ) { + incv(); + } + //while ( ! done ) { + // incv(); + //} + //while ( ! done ) { + // incv(); + //} + } + + public void run() { + try { + Thread t = new Thread(new Runnable() { @Override public void run() { inc(); } }); + t.start(); + Thread.sleep(100); + a = (A) CompileAndDeoptimize.class.getClassLoader().loadClass(B.class.getName().replaceAll("B$", "C")).getConstructors()[0].newInstance(new Object[0]); + //Thread.sleep(1000); + //done = true; + //t.join(); + + } catch ( Throwable t ) { + t.printStackTrace(); + } + } + +} diff --git a/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/MetaspaceStresser.java b/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/MetaspaceStresser.java new file mode 100644 index 00000000000..dd7b1210250 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/MetaspaceStresser.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package vm.share.vmstresser; + +import java.util.*; +import java.util.concurrent.locks.*; + +import nsk.share.*; +import nsk.share.classload.*; +import nsk.share.test.*; + +/** + * Stresser that load classes until OOME, then unload some of them and continue loading. + */ +public class MetaspaceStresser extends Thread { + + /** + * Capacity of class containers. + * This amount of classes will be unloaded on reset call. + */ + public static final int DEFAULT_BUCKET_SIZE = 4000; + + public static final int DEFAULT_PAUSE_TIME = 0; + + /* + * Loaded classes stored in ClassContainer instances. + * Such instances organized in array-based stack as it is + * one of the simplest way to minimize possibility + * to get OOME and guarntee that after replacing + * reference to class container by null there will be + * no cached refereces and container will be reclaimed by + * GC and classes will become unloadable. + */ + // Maximum available amount of arrays with class containers. + private static final int CONTAINERS_ARRAY_LENGTH = 1000; + // Maximum length array with class containers. + private static final int CONTAINER_ARRAYS_COUNT = 100; + + private ClassContainersStack containersStack = new ClassContainersStack(CONTAINER_ARRAYS_COUNT * CONTAINERS_ARRAY_LENGTH, + CONTAINERS_ARRAY_LENGTH); + private ClassContainer newContainer = null; + + private ExecutionController controller = null; + private int bucketSize = DEFAULT_BUCKET_SIZE; + private int pauseTime = DEFAULT_PAUSE_TIME; + + private ReentrantLock lock = new ReentrantLock(); + + /** + * Construct MetaspaceStrresser with default bucket size + * and pause time. + * @param c controller to control execution time. + */ + public MetaspaceStresser(ExecutionController c) { + controller = c; + } + + /** + * Construct MetaspaceStrresser with custom bucket size + * and pause time. + * @param c controller to control execution time. + * @param bucketSize classes to be unloaded on reset. + * @param pauseTime pause after reset. + */ + public MetaspaceStresser(ExecutionController c, int bucketSize, int pauseTime) { + this(c); + this.bucketSize = bucketSize; + this.pauseTime = pauseTime; + } + + /** + * Fill Metaspace with classes. + * Classes will be loaded until OOME, then some of them will be unloaded. + */ + public synchronized void prepare() { + while (controller.continueExecution()) { + try { + fillContainerStack(); + } catch (OutOfMemoryError oome) { + unloadLastClassBucket(); + return; + } catch (ClassNotFoundException cnfe) { + throw new TestBug("Unexpected exception in stresser.", cnfe); + } + } + } + + /** + * Load new class to container, fill containerStack. + * Classes will be loaded until OOME + * @throws ClassNotFoundException + */ + private void fillContainerStack() throws ClassNotFoundException { + newContainer = new ClassContainer(); + while (newContainer.size() < bucketSize && controller.continueExecution()) { + newContainer.loadClass(); + } + containersStack.push(newContainer); + newContainer = null; + } + + /** + * Run stresser. + * Stresser will load classes until OOME, then bucketSize classes + * will be unloaded and stresser will wait pauseTime millisiconds + * before continuing class loading. + */ + public void run() { + try { + while (controller.continueExecution()) { + try { + fillContainerStack(); + } catch (OutOfMemoryError oome) { + unloadLastClassBucket(); + try { + Thread.sleep(pauseTime); + } catch (InterruptedException ie) { + } + } + } + } catch (Throwable e) { + throw new TestBug("Unexpected exception in stresser.", e); + } finally { + containersStack.free(); + } + } + + /** + * Unload most recently loaded bucket of classes. + */ + public void unloadLastClassBucket() { + while (controller.continueExecution()) { + try { + containersStack.pop(); + System.gc(); + break; + } catch (OutOfMemoryError oome) { + oome.printStackTrace(); + continue; + } + } + } + + /** + * Array-based stack for ClassContainer's. + */ + private class ClassContainersStack { + + private int arrayLength = 0; + private int arraysCount = 0; + private int arrayIndex = 0; + private int elemIndex = 0; + + private ClassContainer data[][]; + + /** + * Create ClassContainersStack that will be able + * to store size classes in arrays of segmentSize length. + */ + public ClassContainersStack(int size, int segementSize) { + arrayLength = segementSize; + arraysCount = size / arrayLength; + data = new ClassContainer[arraysCount][]; + data[0] = new ClassContainer[arrayLength]; + } + + /** + * Push ClassContainer c into stack. + */ + public synchronized void push(ClassContainer c) { + data[arrayIndex][elemIndex] = c; + elemIndex++; + if (elemIndex == arrayLength) { + if (arrayIndex == arraysCount) { + throw new TestBug("ClassContainersStack ran out of available slots"); + } + data[arrayIndex + 1] = new ClassContainer[arrayLength]; + arrayIndex++; + elemIndex = 0; + } + } + + /** + * Remove reference to top ClassContainer. + */ + public synchronized void pop() { + data[arrayIndex][elemIndex] = null; + if (elemIndex > 0) { + elemIndex--; + } else if (arrayIndex > 0) { + data[arrayIndex] = null; + arrayIndex--; + elemIndex = arrayLength - 1; + } + } + + /** + * Remove all stored ClassContainers. + */ + public synchronized void free() { + data = null; + System.gc(); + data = new ClassContainer[arraysCount][]; + data[0] = new ClassContainer[arrayLength]; + arrayIndex = 0; + elemIndex = 0; + } + + } + + /// Variable used to create uniqe name for generated classes. + private static long lastClass = 0; + + /** + * Class container consists of classes and their ClassLoader, so + * if there will be no references to container and classes inside it then + * it could be easely collected by GC. + */ + private class ClassContainer { + + private List classes = new LinkedList(); + private GeneratingClassLoader loader = new GeneratingClassLoader(); + private String prefix = loader.getPrefix(); + private int length = loader.getNameLength(); + + public void loadClass() throws ClassNotFoundException { + String newName = prefix + "c" + lastClass; + lastClass++; + while (newName.length() < length) { + newName = newName + "c"; + } + classes.add(loader.loadClass(newName)); + } + + public int size() { + return classes.size(); + } + } + +} From d05ed512ac0c3957a8320fbac21bbcd323594de8 Mon Sep 17 00:00:00 2001 From: John Rose Date: Mon, 30 Apr 2018 21:56:54 -0400 Subject: [PATCH 090/102] 8200167: Validate more special case invocations Co-authored-by: Vladimir Ivanov Co-authored-by: Tobias Hartmann Reviewed-by: acorn, vlivanov, dholmes --- src/hotspot/share/c1/c1_Canonicalizer.cpp | 4 +- .../java/lang/invoke/DirectMethodHandle.java | 70 +++-- .../lang/invoke/InvokerBytecodeGenerator.java | 1 + .../classes/java/lang/invoke/LambdaForm.java | 3 +- .../java/lang/invoke/MethodHandles.java | 26 +- .../java/lang/invoke/MethodTypeForm.java | 5 +- test/jdk/java/lang/invoke/I4Special.jcod | 106 ++++++++ .../lang/invoke/SpecialInterfaceCall.java | 254 ++++++++++++++++++ 8 files changed, 431 insertions(+), 38 deletions(-) create mode 100644 test/jdk/java/lang/invoke/I4Special.jcod create mode 100644 test/jdk/java/lang/invoke/SpecialInterfaceCall.java diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp index c4730e9b23c..78cf3f4e59c 100644 --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -648,7 +648,7 @@ void Canonicalizer::do_NewTypeArray (NewTypeArray* x) {} void Canonicalizer::do_NewObjectArray (NewObjectArray* x) {} void Canonicalizer::do_NewMultiArray (NewMultiArray* x) {} void Canonicalizer::do_CheckCast (CheckCast* x) { - if (x->klass()->is_loaded()) { + if (x->klass()->is_loaded() && !x->is_invokespecial_receiver_check()) { Value obj = x->obj(); ciType* klass = obj->exact_type(); if (klass == NULL) klass = obj->declared_type(); diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index 696222940d7..388aa7a5797 100644 --- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,26 +72,30 @@ class DirectMethodHandle extends MethodHandle { } // Factory methods: - static DirectMethodHandle make(byte refKind, Class receiver, MemberName member) { + static DirectMethodHandle make(byte refKind, Class refc, MemberName member, Class callerClass) { MethodType mtype = member.getMethodOrFieldType(); if (!member.isStatic()) { - if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor()) + if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor()) throw new InternalError(member.toString()); - mtype = mtype.insertParameterTypes(0, receiver); + mtype = mtype.insertParameterTypes(0, refc); } if (!member.isField()) { switch (refKind) { case REF_invokeSpecial: { member = member.asSpecial(); - LambdaForm lform = preparedLambdaForm(member); - return new Special(mtype, lform, member); + LambdaForm lform = preparedLambdaForm(member, callerClass); + Class checkClass = refc; // Class to use for receiver type check + if (callerClass != null) { + checkClass = callerClass; // potentially strengthen to caller class + } + return new Special(mtype, lform, member, checkClass); } case REF_invokeInterface: { - LambdaForm lform = preparedLambdaForm(member); - return new Interface(mtype, lform, member, receiver); + LambdaForm lform = preparedLambdaForm(member, callerClass); + return new Interface(mtype, lform, member, refc); } default: { - LambdaForm lform = preparedLambdaForm(member); + LambdaForm lform = preparedLambdaForm(member, callerClass); return new DirectMethodHandle(mtype, lform, member); } } @@ -108,11 +112,11 @@ class DirectMethodHandle extends MethodHandle { } } } - static DirectMethodHandle make(Class receiver, MemberName member) { + static DirectMethodHandle make(Class refc, MemberName member) { byte refKind = member.getReferenceKind(); if (refKind == REF_invokeSpecial) refKind = REF_invokeVirtual; - return make(refKind, receiver, member); + return make(refKind, refc, member, null /* no callerClass context */); } static DirectMethodHandle make(MemberName member) { if (member.isConstructor()) @@ -161,7 +165,7 @@ class DirectMethodHandle extends MethodHandle { * Cache and share this structure among all methods with * the same basicType and refKind. */ - private static LambdaForm preparedLambdaForm(MemberName m) { + private static LambdaForm preparedLambdaForm(MemberName m, Class callerClass) { assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead MethodType mtype = m.getInvocationType().basicType(); assert(!m.isMethodHandleInvoke()) : m; @@ -179,6 +183,9 @@ class DirectMethodHandle extends MethodHandle { preparedLambdaForm(mtype, which); which = LF_INVSTATIC_INIT; } + if (which == LF_INVSPECIAL && callerClass != null && callerClass.isInterface()) { + which = LF_INVSPECIAL_IFC; + } LambdaForm lform = preparedLambdaForm(mtype, which); maybeCompile(lform, m); assert(lform.methodType().dropParameterTypes(0, 1) @@ -187,6 +194,10 @@ class DirectMethodHandle extends MethodHandle { return lform; } + private static LambdaForm preparedLambdaForm(MemberName m) { + return preparedLambdaForm(m, null); + } + private static LambdaForm preparedLambdaForm(MethodType mtype, int which) { LambdaForm lform = mtype.form().cachedLambdaForm(which); if (lform != null) return lform; @@ -197,13 +208,16 @@ class DirectMethodHandle extends MethodHandle { static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) { boolean needsInit = (which == LF_INVSTATIC_INIT); boolean doesAlloc = (which == LF_NEWINVSPECIAL); - boolean needsReceiverCheck = (which == LF_INVINTERFACE); + boolean needsReceiverCheck = (which == LF_INVINTERFACE || + which == LF_INVSPECIAL_IFC); + String linkerName; LambdaForm.Kind kind; switch (which) { case LF_INVVIRTUAL: linkerName = "linkToVirtual"; kind = DIRECT_INVOKE_VIRTUAL; break; case LF_INVSTATIC: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC; break; case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC_INIT; break; + case LF_INVSPECIAL_IFC:linkerName = "linkToSpecial"; kind = DIRECT_INVOKE_SPECIAL_IFC; break; case LF_INVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_INVOKE_SPECIAL; break; case LF_INVINTERFACE: linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE; break; case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_NEW_INVOKE_SPECIAL; break; @@ -376,8 +390,10 @@ class DirectMethodHandle extends MethodHandle { /** This subclass represents invokespecial instructions. */ static class Special extends DirectMethodHandle { - private Special(MethodType mtype, LambdaForm form, MemberName member) { + private final Class caller; + private Special(MethodType mtype, LambdaForm form, MemberName member, Class caller) { super(mtype, form, member); + this.caller = caller; } @Override boolean isInvokeSpecial() { @@ -385,7 +401,15 @@ class DirectMethodHandle extends MethodHandle { } @Override MethodHandle copyWith(MethodType mt, LambdaForm lf) { - return new Special(mt, lf, member); + return new Special(mt, lf, member, caller); + } + Object checkReceiver(Object recv) { + if (!caller.isInstance(recv)) { + String msg = String.format("Receiver class %s is not a subclass of caller class %s", + recv.getClass().getName(), caller.getName()); + throw new IncompatibleClassChangeError(msg); + } + return recv; } } @@ -401,17 +425,23 @@ class DirectMethodHandle extends MethodHandle { MethodHandle copyWith(MethodType mt, LambdaForm lf) { return new Interface(mt, lf, member, refc); } - + @Override Object checkReceiver(Object recv) { if (!refc.isInstance(recv)) { - String msg = String.format("Class %s does not implement the requested interface %s", - recv.getClass().getName(), refc.getName()); + String msg = String.format("Receiver class %s does not implement the requested interface %s", + recv.getClass().getName(), refc.getName()); throw new IncompatibleClassChangeError(msg); } return recv; } } + /** Used for interface receiver type checks, by Interface and Special modes. */ + Object checkReceiver(Object recv) { + throw new InternalError("Should only be invoked on a subclass"); + } + + /** This subclass handles constructor references. */ static class Constructor extends DirectMethodHandle { final MemberName initMethod; @@ -823,10 +853,10 @@ class DirectMethodHandle extends MethodHandle { MemberName.getFactory() .resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class)); case NF_checkReceiver: - member = new MemberName(Interface.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual); + member = new MemberName(DirectMethodHandle.class, "checkReceiver", OBJ_OBJ_TYPE, REF_invokeVirtual); return new NamedFunction( MemberName.getFactory() - .resolveOrFail(REF_invokeVirtual, member, Interface.class, NoSuchMethodException.class)); + .resolveOrFail(REF_invokeVirtual, member, DirectMethodHandle.class, NoSuchMethodException.class)); default: throw newInternalError("Unknown function: " + func); } diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index c37ba71b2a0..1770fba2a0c 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -674,6 +674,7 @@ class InvokerBytecodeGenerator { case DIRECT_NEW_INVOKE_SPECIAL: // fall-through case DIRECT_INVOKE_INTERFACE: // fall-through case DIRECT_INVOKE_SPECIAL: // fall-through + case DIRECT_INVOKE_SPECIAL_IFC: // fall-through case DIRECT_INVOKE_STATIC: // fall-through case DIRECT_INVOKE_STATIC_INIT: // fall-through case DIRECT_INVOKE_VIRTUAL: return resolveFrom(name, invokerType, DirectMethodHandle.Holder.class); diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java index 42bbf6257ac..139038bcdbd 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -291,6 +291,7 @@ class LambdaForm { LINK_TO_CALL_SITE("linkToCallSite"), DIRECT_INVOKE_VIRTUAL("DMH.invokeVirtual", "invokeVirtual"), DIRECT_INVOKE_SPECIAL("DMH.invokeSpecial", "invokeSpecial"), + DIRECT_INVOKE_SPECIAL_IFC("DMH.invokeSpecialIFC", "invokeSpecialIFC"), DIRECT_INVOKE_STATIC("DMH.invokeStatic", "invokeStatic"), DIRECT_NEW_INVOKE_SPECIAL("DMH.newInvokeSpecial", "newInvokeSpecial"), DIRECT_INVOKE_INTERFACE("DMH.invokeInterface", "invokeInterface"), diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 0277a8e24e2..fa8f2b4f4f9 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2267,27 +2267,27 @@ return mh1; } /** Check access and get the requested method. */ - private MethodHandle getDirectMethod(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { + private MethodHandle getDirectMethod(byte refKind, Class refc, MemberName method, Class boundCallerClass) throws IllegalAccessException { final boolean doRestrict = true; final boolean checkSecurity = true; - return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, boundCallerClass); } /** Check access and get the requested method, for invokespecial with no restriction on the application of narrowing rules. */ - private MethodHandle getDirectMethodNoRestrictInvokeSpecial(Class refc, MemberName method, Class callerClass) throws IllegalAccessException { + private MethodHandle getDirectMethodNoRestrictInvokeSpecial(Class refc, MemberName method, Class boundCallerClass) throws IllegalAccessException { final boolean doRestrict = false; final boolean checkSecurity = true; - return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, callerClass); + return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, boundCallerClass); } /** Check access and get the requested method, eliding security manager checks. */ - private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class refc, MemberName method, Class callerClass) throws IllegalAccessException { + private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class refc, MemberName method, Class boundCallerClass) throws IllegalAccessException { final boolean doRestrict = true; final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants - return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass); + return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, boundCallerClass); } /** Common code for all methods; do not call directly except from immediately above. */ private MethodHandle getDirectMethodCommon(byte refKind, Class refc, MemberName method, boolean checkSecurity, - boolean doRestrict, Class callerClass) throws IllegalAccessException { + boolean doRestrict, Class boundCallerClass) throws IllegalAccessException { checkMethod(refKind, refc, method); // Optionally check with the security manager; this isn't needed for unreflect* calls. if (checkSecurity) @@ -2325,25 +2325,25 @@ return mh1; checkMethod(refKind, refc, method); } - DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method); + DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method, lookupClass()); MethodHandle mh = dmh; - // Optionally narrow the receiver argument to refc using restrictReceiver. + // Optionally narrow the receiver argument to lookupClass using restrictReceiver. if ((doRestrict && refKind == REF_invokeSpecial) || (MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(method))) { mh = restrictReceiver(method, dmh, lookupClass()); } - mh = maybeBindCaller(method, mh, callerClass); + mh = maybeBindCaller(method, mh, boundCallerClass); mh = mh.setVarargs(method); return mh; } private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, - Class callerClass) + Class boundCallerClass) throws IllegalAccessException { if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) return mh; Class hostClass = lookupClass; if (!hasPrivateAccess()) // caller must have private access - hostClass = callerClass; // callerClass came from a security manager style stack walk + hostClass = boundCallerClass; // boundCallerClass came from a security manager style stack walk MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass); // Note: caller will apply varargs after this step happens. return cbmh; diff --git a/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java b/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java index c67ea418a6c..9b218319152 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,8 @@ final class MethodTypeForm { LF_GWT = 17, // guardWithTest LF_TF = 18, // tryFinally LF_LOOP = 19, // loop - LF_LIMIT = 20; + LF_INVSPECIAL_IFC = 20, // DMH invokeSpecial of (private) interface method + LF_LIMIT = 21; /** Return the type corresponding uniquely (1-1) to this MT-form. * It might have any primitive returns or arguments, but will have no references except Object. diff --git a/test/jdk/java/lang/invoke/I4Special.jcod b/test/jdk/java/lang/invoke/I4Special.jcod new file mode 100644 index 00000000000..a54aa5d753f --- /dev/null +++ b/test/jdk/java/lang/invoke/I4Special.jcod @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// invokeDirect is modified to use invokespecial instead of invokevirtual + +class SpecialInterfaceCall$I4 { + 0xCAFEBABE; + 0; // minor version + 55; // version + [] { // Constant Pool + ; // first element is empty + Method #3 #13; // #1 + class #15; // #2 + class #16; // #3 + class #17; // #4 + Utf8 "invokeDirect"; // #5 + Utf8 "I4"; // #6 + Utf8 "InnerClasses"; // #7 + Utf8 "(LSpecialInterfaceCall$I4;)V"; // #8 + Utf8 "Code"; // #9 + Utf8 "LineNumberTable"; // #10 + Utf8 "SourceFile"; // #11 + Utf8 "SpecialInterfaceCall.java"; // #12 + NameAndType #19 #20; // #13 + class #21; // #14 + Utf8 "SpecialInterfaceCall$I4"; // #15 + Utf8 "java/lang/Object"; // #16 + Utf8 "SpecialInterfaceCall$I1"; // #17 + Utf8 "I1"; // #18 + Utf8 "toString"; // #19 + Utf8 "()Ljava/lang/String;"; // #20 + Utf8 "SpecialInterfaceCall"; // #21 + } // Constant Pool + + 0x0600; // access + #2;// this_cpx + #3;// super_cpx + + [] { // Interfaces + #4; + } // Interfaces + + [] { // fields + } // fields + + [] { // methods + { // Member + 0x0009; // access + #5; // name_cpx + #8; // sig_cpx + [] { // Attributes + Attr(#9) { // Code + 1; // max_stack + 2; // max_locals + Bytes[]{ +// 0x2AB600014CB1; + 0x2AB700014CB1; // invokespecial + }; + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#10) { // LineNumberTable + [] { // LineNumberTable + 0 77; + 5 78; + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [] { // Attributes + Attr(#11) { // SourceFile + #12; + } // end SourceFile + ; + Attr(#7) { // InnerClasses + [] { // InnerClasses + #2 #14 #6 1544; + #4 #14 #18 1544; + } + } // end InnerClasses + } // Attributes +} // end class SpecialInterfaceCall$I4 diff --git a/test/jdk/java/lang/invoke/SpecialInterfaceCall.java b/test/jdk/java/lang/invoke/SpecialInterfaceCall.java new file mode 100644 index 00000000000..e651845344b --- /dev/null +++ b/test/jdk/java/lang/invoke/SpecialInterfaceCall.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8200167 + * @summary Test direct and MethodHandle access to interface methods using invokespecial semantics + * @compile SpecialInterfaceCall.java + * @compile I4Special.jcod + * @run main/othervm -Xint SpecialInterfaceCall + * @run main/othervm -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 SpecialInterfaceCall + * @run main/othervm -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=2 SpecialInterfaceCall + * @run main/othervm -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=3 SpecialInterfaceCall + * @run main/othervm -Xbatch -XX:-TieredCompilation SpecialInterfaceCall + */ + +import java.lang.invoke.*; + +public class SpecialInterfaceCall { + interface I1 { + default void pub_m() {}; + private void priv_m() {}; + } + interface I2 extends I1 { + // This needs to be a public method to avoid access control issues, + // but logically we treat it as private and emulate invokespecial + // using MethodHandles. + default void pub_m() {}; + + private void priv_m() {}; + + static void invokeDirect(I2 i) { + i.priv_m(); // generates invokespecial + } + static void invokeSpecialMH(I2 i) throws Throwable { + // emulates behaviour of invokeDirect + mh_I2_priv_m_from_I2.invokeExact(i); + } + // special case of invoking an Object method via an interface + static void invokeSpecialObjectMH(I2 i) throws Throwable { + // emulates invokespecial of I1.toString on i, which resolves + // to Object.toString + String s = (String) mh_I1_toString_from_I2.invokeExact(i); + } + } + interface I3 extends I2 { + // Must take an I3 here rather than I2 else we get + // WrongMethodTypeException: expected (I3)void but found (I2)void + // Statically the receiver type is bounded by the caller type. + static void invokeSpecialMH(I3 i) throws Throwable { + // emulates an invokespecial of ((I2)i).pub_m() + mh_I2_pub_m_from_I3.invokeExact(i); + } + } + // This interface acts like I2 but we define a directInvoke method + // that we will rewrite the bytecode of to use invokespecial + interface I4 extends I1 { + static void invokeDirect(I4 i) { + String s = i.toString(); + } + } + + // Concrete classes + static class C1 implements I1 { } + static class C2 implements I2 { } + static class C3 implements I3 { } + static class C4 implements I4 { } + + // Classes that don't implement I2/I3 but do have a + // priv_m/pub_m method in their hierarchy + static class D1 implements I1 { } + static class E { + public void pub_m() {} + private void priv_m() {} + } + + // This MH acts like the direct invokespecial in I2.invokeDirect + static final MethodHandle mh_I2_priv_m_from_I2; + + // This MH acts like an invokespecial of I2.pub_m from I3 + static final MethodHandle mh_I2_pub_m_from_I3; + + // This MH acts likes an invokespecial of I1.toString from I2 + static final MethodHandle mh_I1_toString_from_I2; + static { + try { + MethodType mt = MethodType.methodType(void.class); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + + mh_I2_priv_m_from_I2 = lookup.findSpecial(I2.class, "priv_m", mt, I2.class); + mh_I2_pub_m_from_I3 = lookup.findSpecial(I2.class, "pub_m", mt, I3.class); + + mt = MethodType.methodType(String.class); + mh_I1_toString_from_I2 = lookup.findSpecial(I1.class, "toString", mt, I2.class); + + } catch (Throwable e) { + throw new Error(e); + } + } + + static void runPositiveTests() { + shouldNotThrow(() -> I2.invokeDirect(new C2())); + shouldNotThrow(() -> I2.invokeDirect(new C3())); + shouldNotThrow(() -> I2.invokeSpecialMH(new C2())); + shouldNotThrow(() -> I2.invokeSpecialMH(new C3())); + + shouldNotThrow(() -> I3.invokeSpecialMH(new C3())); + + shouldNotThrow(() -> I4.invokeDirect(new C4())); + } + + static void runNegativeTests() { + System.out.println("IAE I2.invokeDirect D1"); + shouldThrowIAE(() -> I2.invokeDirect(unsafeCastI2(new D1()))); + System.out.println("IAE I2.invokeDirect E"); + shouldThrowIAE(() -> I2.invokeDirect(unsafeCastI2(new E()))); + System.out.println("ICCE I2.invokeMH D1"); + shouldThrowICCE(() -> I2.invokeSpecialMH(unsafeCastI2(new D1()))); + System.out.println("ICCE I2.invokeMH E"); + shouldThrowICCE(() -> I2.invokeSpecialMH(unsafeCastI2(new E()))); + System.out.println("ICCE I3.invokeMH D1"); + shouldThrowICCE(() -> I3.invokeSpecialMH(unsafeCastI3(new D1()))); + System.out.println("ICCE I3.invokeMH E"); + shouldThrowICCE(() -> I3.invokeSpecialMH(unsafeCastI3(new E()))); + System.out.println("ICCE I3.invokeMH C2"); + shouldThrowICCE(() -> I3.invokeSpecialMH(unsafeCastI3(new C2()))); + System.out.println("ICCE I4.invokeDirect C1"); + shouldThrowIAE(() -> I4.invokeDirect(unsafeCastI4(new C1()))); + System.out.println("ICCE I2.invokeObjectMH C1"); + shouldThrowICCE(() -> I2.invokeSpecialObjectMH(unsafeCastI2(new C1()))); + + } + + static void warmup() { + for (int i = 0; i < 20_000; i++) { + runPositiveTests(); + } + } + + public static void main(String[] args) throws Throwable { + System.out.println("UNRESOLVED:"); + runNegativeTests(); + runPositiveTests(); + + System.out.println("RESOLVED:"); + runNegativeTests(); + + System.out.println("WARMUP:"); + warmup(); + + System.out.println("COMPILED:"); + runNegativeTests(); + runPositiveTests(); + } + + static interface Test { + void run() throws Throwable; + } + + static void shouldThrowICCE(Test t) { + shouldThrow(IncompatibleClassChangeError.class, + "is not a subclass of caller class", t); + } + + static void shouldThrowIAE(Test t) { + shouldThrow(IllegalAccessError.class, + "must be the current class or a subtype of interface", t); + } + + static void shouldThrow(Class expectedError, String reason, Test t) { + try { + t.run(); + } catch (Throwable e) { + if (expectedError.isInstance(e)) { + if (e.getMessage().contains(reason)) { + // passed + System.out.println("Threw expected: " + e); + return; + } + else { + throw new AssertionError("Wrong exception reason: expected '" + reason + + "', got '" + e.getMessage() + "'", e); + } + } else { + String msg = String.format("Wrong exception thrown: expected=%s; thrown=%s", + expectedError.getName(), e.getClass().getName()); + throw new AssertionError(msg, e); + } + } + throw new AssertionError("No exception thrown: expected " + expectedError.getName()); + } + + static void shouldNotThrow(Test t) { + try { + t.run(); + // passed + } catch (Throwable e) { + throw new AssertionError("Exception was thrown: ", e); + } + } + + // Note: these unsafe casts are only possible for interface types + + static I2 unsafeCastI2(Object obj) { + try { + MethodHandle mh = MethodHandles.identity(Object.class); + mh = MethodHandles.explicitCastArguments(mh, mh.type().changeReturnType(I2.class)); + return (I2)mh.invokeExact((Object) obj); + } catch (Throwable e) { + throw new Error(e); + } + } + + static I3 unsafeCastI3(Object obj) { + try { + MethodHandle mh = MethodHandles.identity(Object.class); + mh = MethodHandles.explicitCastArguments(mh, mh.type().changeReturnType(I3.class)); + return (I3)mh.invokeExact((Object) obj); + } catch (Throwable e) { + throw new Error(e); + } + } + + static I4 unsafeCastI4(Object obj) { + try { + MethodHandle mh = MethodHandles.identity(Object.class); + mh = MethodHandles.explicitCastArguments(mh, mh.type().changeReturnType(I4.class)); + return (I4)mh.invokeExact((Object) obj); + } catch (Throwable e) { + throw new Error(e); + } + } + +} From 3c202e01d8a41437bf542f3e91ffaea38ae910e8 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 1 May 2018 07:40:41 -0400 Subject: [PATCH 091/102] 8201542: Remove unused _gc_timer field in GCMemoryManager Minor cleanup to remove unused field Reviewed-by: shade, minqi --- src/hotspot/share/services/memoryManager.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/services/memoryManager.hpp b/src/hotspot/share/services/memoryManager.hpp index 46fe322d3ec..621812c6e58 100644 --- a/src/hotspot/share/services/memoryManager.hpp +++ b/src/hotspot/share/services/memoryManager.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,6 @@ private: // TODO: We should unify the GCCounter and GCMemoryManager statistic size_t _num_collections; elapsedTimer _accumulated_timer; - elapsedTimer _gc_timer; // for measuring every GC duration GCStatInfo* _last_gc_stat; Mutex* _last_gc_lock; GCStatInfo* _current_gc_stat; From a4c59341694987565eee0f3f3fe0592a47e832f0 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Tue, 1 May 2018 06:18:48 -0700 Subject: [PATCH 092/102] 8202373: Forcing eager initialization of CHM$ReservationNode avoids deoptimization Reviewed-by: martin, psandoz, dholmes, redestad --- .../share/classes/java/util/concurrent/ConcurrentHashMap.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java index 0a0ac3eef5f..c09e9a2c140 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -6389,5 +6389,8 @@ public class ConcurrentHashMap extends AbstractMap // Reduce the risk of rare disastrous classloading in first call to // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773 Class ensureLoaded = LockSupport.class; + + // Eager class load observed to help JIT during startup + ensureLoaded = ReservationNode.class; } } From 0e7d8874a96178c0321f71b81c9250db55fd4e49 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 1 May 2018 19:13:31 +0200 Subject: [PATCH 093/102] 8202379: ARM32 is broken after JDK-8201543 (Modularize C1 GC barriers) Reviewed-by: aph, eosterlund --- src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp | 23 ++++--------------- src/hotspot/cpu/arm/c1_Runtime1_arm.cpp | 4 ++-- .../arm/gc/g1/g1BarrierSetAssembler_arm.cpp | 21 +++-------------- .../arm/gc/g1/g1BarrierSetAssembler_arm.hpp | 1 + src/hotspot/share/c1/c1_LIRGenerator.hpp | 4 ++++ 5 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index e298140724c..706fb908953 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -375,32 +375,17 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, } -LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type, bool needs_card_mark) { +LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type) { int base_offset = arrayOopDesc::base_offset_in_bytes(type); int elem_size = type2aelembytes(type); if (index_opr->is_constant()) { int offset = base_offset + index_opr->as_constant_ptr()->as_jint() * elem_size; - if (needs_card_mark) { - LIR_Opr base_opr = new_pointer_register(); - add_large_constant(array_opr, offset, base_opr); - return new LIR_Address(base_opr, (intx)0, type); - } else { - return generate_address(array_opr, offset, type); - } + return generate_address(array_opr, offset, type); } else { assert(index_opr->is_register(), "must be"); int scale = exact_log2(elem_size); - if (needs_card_mark) { - LIR_Opr base_opr = new_pointer_register(); - LIR_Address* addr = make_address(base_opr, index_opr, (LIR_Address::Scale)scale, type); - __ add(array_opr, LIR_OprFact::intptrConst(base_offset), base_opr); - __ add(base_opr, LIR_OprFact::address(addr), base_opr); // add with shifted/extended register - return new LIR_Address(base_opr, type); - } else { - return generate_address(array_opr, index_opr, scale, base_offset, type); - } + return generate_address(array_opr, index_opr, scale, base_offset, type); } } @@ -1024,7 +1009,7 @@ LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) value.load_item(); assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); LIR_Opr tmp = (UseCompressedOops && is_oop) ? new_pointer_register() : LIR_OprFact::illegalOpr; - __ xchg(addr_ptr, data, dst, tmp); + __ xchg(addr, value.result(), result, tmp); return result; } diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 885da76601d..3a9846928c3 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -352,11 +352,11 @@ static void restore_live_registers_without_return(StubAssembler* sasm, bool rest } void StubAssembler::save_live_registers() { - save_live_registers(this); + ::save_live_registers(this); } void StubAssembler::restore_live_registers_without_return() { - restore_live_registers_without_return(this); + ::restore_live_registers_without_return(this); } void Runtime1::initialize_pd() { diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index b351deb1843..cab07afbe9f 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -26,6 +26,7 @@ #include "asm/macroAssembler.inline.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" +#include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/heapRegion.hpp" #include "interpreter/interp_masm.hpp" @@ -175,15 +176,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* // Input: // - pre_val pushed on the stack - __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ mov(R0, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0); - __ should_not_reach_here(); - break; - } + __ set_info("g1_pre_barrier_slow_id", false); // save at least the registers that need saving if the runtime is called #ifdef AARCH64 @@ -251,15 +244,7 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* // Input: // - store_addr, pushed on the stack - __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); - - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs->kind() != BarrierSet::G1BarrierSet) { - __ mov(R0, (int)id); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0); - __ should_not_reach_here(); - break; - } + __ set_info("g1_post_barrier_slow_id", false); Label done; Label recheck; diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp index babc24cc8ec..404dc916730 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp @@ -42,6 +42,7 @@ protected: Register addr, Register count, Register tmp); #ifdef COMPILER1 +public: void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index c991c27d8fd..5f152cff6e3 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -302,6 +302,10 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { LIR_Opr atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& new_value); LIR_Opr atomic_add(BasicType type, LIR_Opr addr, LIRItem& new_value); +#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER + virtual void CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LIR_Const* card_table_base); +#endif + // specific implementations void array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci); From d071f0e34476bbec9dfc590e59f45b1278b7ae1d Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 1 May 2018 12:37:15 -0700 Subject: [PATCH 094/102] 8202484: Unused field in TimeZone Reviewed-by: lancea --- src/java.base/share/classes/java/util/TimeZone.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/util/TimeZone.java b/src/java.base/share/classes/java/util/TimeZone.java index b428cd668a7..2922e44a86a 100644 --- a/src/java.base/share/classes/java/util/TimeZone.java +++ b/src/java.base/share/classes/java/util/TimeZone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -784,9 +784,6 @@ public abstract class TimeZone implements Serializable, Cloneable { static final String GMT_ID = "GMT"; private static final int GMT_ID_LENGTH = 3; - // a static TimeZone we can reference if no AppContext is in place - private static volatile TimeZone mainAppContextDefault; - /** * Parses a custom time zone identifier and returns a corresponding zone. * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm) From 285bf7bbb4bd76b4fef0474e1daa85873f118e7a Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 1 May 2018 14:40:31 -0700 Subject: [PATCH 095/102] 8202507: Remove IO and NIO AtomicAppend tests from problem list Reviewed-by: lancea --- test/jdk/ProblemList.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 14fa4bcf0ae..78e9fdd5e69 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -510,7 +510,6 @@ java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8081652 generic- # jdk_io -java/io/FileOutputStream/AtomicAppend.java 8202062 macosx-all java/io/pathNames/GeneralWin32.java 8180264 windows-all java/io/FileInputStream/UnreferencedFISClosesFd.java 8202292 linux-all @@ -552,8 +551,6 @@ java/nio/Buffer/EqualsCompareTest.java 8193917 solaris- java/nio/channels/DatagramChannel/ChangingAddress.java 7141822 macosx-all -java/nio/channels/FileChannel/AtomicAppend.java 8202062 macosx-all - java/nio/channels/Selector/Wakeup.java 6963118 windows-all java/nio/file/WatchService/Basic.java 7158947 solaris-all Solaris 11 From e8fff780938727224490c71abd53fad0f3089a95 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 1 May 2018 17:19:18 -0700 Subject: [PATCH 096/102] 8202334: Update javax.lang.model.util visitors for 11 Reviewed-by: jjg --- .../model/util/AbstractAnnotationValueVisitor9.java | 8 ++++---- .../lang/model/util/AbstractElementVisitor9.java | 8 ++++---- .../javax/lang/model/util/AbstractTypeVisitor9.java | 8 ++++---- .../javax/lang/model/util/ElementKindVisitor9.java | 12 +++++++----- .../javax/lang/model/util/ElementScanner9.java | 9 +++++---- .../model/util/SimpleAnnotationValueVisitor9.java | 9 +++++---- .../javax/lang/model/util/SimpleElementVisitor9.java | 8 ++++---- .../javax/lang/model/util/SimpleTypeVisitor9.java | 11 ++++++----- .../javax/lang/model/util/TypeKindVisitor9.java | 12 +++++++----- 9 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor9.java index c05736913e7..f7c163b3cd7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,8 @@ import javax.annotation.processing.SupportedSourceVersion; /** * A skeletal visitor for annotation values with default behavior - * appropriate for the {@link SourceVersion#RELEASE_9 RELEASE_9} - * and {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * appropriate for source versions {@link SourceVersion#RELEASE_9 + * RELEASE_9} through {@link SourceVersion#RELEASE_11 RELEASE_11}. * *

      WARNING: The {@code AnnotationValueVisitor} interface * implemented by this class may have methods added to it in the @@ -59,7 +59,7 @@ import javax.annotation.processing.SupportedSourceVersion; * @see AbstractAnnotationValueVisitor8 * @since 9 */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public abstract class AbstractAnnotationValueVisitor9 extends AbstractAnnotationValueVisitor8 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor9.java index 556c897c950..3c633864609 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,8 @@ import static javax.lang.model.SourceVersion.*; /** * A skeletal visitor of program elements with default behavior - * appropriate for the {@link SourceVersion#RELEASE_9 RELEASE_9} - * and {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * appropriate for source versions {@link SourceVersion#RELEASE_9 + * RELEASE_9} through {@link SourceVersion#RELEASE_11 RELEASE_11}. * *

      WARNING: The {@code ElementVisitor} interface * implemented by this class may have methods added to it in the @@ -65,7 +65,7 @@ import static javax.lang.model.SourceVersion.*; * @since 9 * @spec JPMS */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public abstract class AbstractElementVisitor9 extends AbstractElementVisitor8 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java index b38a032ada7..bfeaa83a59b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,8 @@ import static javax.lang.model.SourceVersion.*; /** * A skeletal visitor of types with default behavior appropriate for - * the {@link SourceVersion#RELEASE_9 RELEASE_9} - * and {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * source versions {@link SourceVersion#RELEASE_9 RELEASE_9} through + * {@link SourceVersion#RELEASE_11 RELEASE_11}. * *

      WARNING: The {@code TypeVisitor} interface implemented * by this class may have methods added to it in the future to @@ -63,7 +63,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor8 * @since 9 */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public abstract class AbstractTypeVisitor9 extends AbstractTypeVisitor8 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java index 7fc8140e8ec..3810ebc22c9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,11 @@ import javax.lang.model.SourceVersion; /** * A visitor of program elements based on their {@linkplain - * ElementKind kind} with default behavior appropriate for the {@link - * SourceVersion#RELEASE_9 RELEASE_9} and {@link - * SourceVersion#RELEASE_10 RELEASE_10} source versions. For {@linkplain + * ElementKind kind} with default behavior appropriate for source + * versions {@link SourceVersion#RELEASE_9 RELEASE_9} through {@link + * SourceVersion#RELEASE_11 RELEASE_11}. + * + * For {@linkplain * Element elements} Xyz that may have more than one * kind, the visitXyz methods in this class delegate * to the visitXyzAsKind method corresponding to the @@ -78,7 +80,7 @@ import javax.lang.model.SourceVersion; * @since 9 * @spec JPMS */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public class ElementKindVisitor9 extends ElementKindVisitor8 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java index a5e61046646..0e7ac388764 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,9 @@ import static javax.lang.model.SourceVersion.*; /** * A scanning visitor of program elements with default behavior - * appropriate for the {@link SourceVersion#RELEASE_9 RELEASE_9} - * and {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * appropriate for source versions {@link SourceVersion#RELEASE_9 + * RELEASE_9} through {@link SourceVersion#RELEASE_11 RELEASE_11}. + * * The visitXyz methods in this * class scan their component elements by calling {@code scan} on * their {@linkplain Element#getEnclosedElements enclosed elements}, @@ -91,7 +92,7 @@ import static javax.lang.model.SourceVersion.*; * @since 9 * @spec JPMS */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public class ElementScanner9 extends ElementScanner8 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor9.java index adb172e092e..bc6c37c3694 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,9 @@ import static javax.lang.model.SourceVersion.*; /** * A simple visitor for annotation values with default behavior - * appropriate for the {@link SourceVersion#RELEASE_9 RELEASE_9} - * and {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * appropriate for source versions {@link SourceVersion#RELEASE_9 + * RELEASE_9} through {@link SourceVersion#RELEASE_11 RELEASE_11}. + * * Visit methods call {@link #defaultAction * defaultAction} passing their arguments to {@code defaultAction}'s * corresponding parameters. @@ -67,7 +68,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor8 * @since 9 */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public class SimpleAnnotationValueVisitor9 extends SimpleAnnotationValueVisitor8 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java index a73988fb3b4..4fe6a95bdee 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,8 @@ import static javax.lang.model.SourceVersion.*; /** * A simple visitor of program elements with default behavior - * appropriate for the {@link SourceVersion#RELEASE_9 RELEASE_9} - * and {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * appropriate for source versions {@link SourceVersion#RELEASE_9 + * RELEASE_9} through {@link SourceVersion#RELEASE_11 RELEASE_11}. * * Visit methods corresponding to {@code RELEASE_9} and earlier * language constructs call {@link #defaultAction defaultAction}, @@ -73,7 +73,7 @@ import static javax.lang.model.SourceVersion.*; * @since 9 * @spec JPMS */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public class SimpleElementVisitor9 extends SimpleElementVisitor8 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java index 41521e20509..07749a37f6d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,9 +31,9 @@ import javax.lang.model.type.IntersectionType; import static javax.lang.model.SourceVersion.*; /** - * A simple visitor of types with default behavior appropriate for the - * {@link SourceVersion#RELEASE_9 RELEASE_9} and - * {@link SourceVersion#RELEASE_10 RELEASE_10} source versions. + * A simple visitor of types with default behavior appropriate for + * source versions {@link SourceVersion#RELEASE_9 RELEASE_9} through + * {@link SourceVersion#RELEASE_11 RELEASE_11}. * * Visit methods corresponding to {@code RELEASE_9} and earlier * language constructs call {@link #defaultAction defaultAction}, @@ -70,9 +70,10 @@ import static javax.lang.model.SourceVersion.*; * * @see SimpleTypeVisitor6 * @see SimpleTypeVisitor7 + * @see SimpleTypeVisitor8 * @since 9 */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public class SimpleTypeVisitor9 extends SimpleTypeVisitor8 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor9.java index 321a7fa311a..51cbeaa5456 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,11 @@ import static javax.lang.model.SourceVersion.*; /** * A visitor of types based on their {@linkplain TypeKind kind} with - * default behavior appropriate for the {@link SourceVersion#RELEASE_9 - * RELEASE_9} and {@link SourceVersion#RELEASE_10 RELEASE_10} source - * versions. For {@linkplain + * default behavior appropriate for source versions {@link + * SourceVersion#RELEASE_9 RELEASE_9} through {@link + * SourceVersion#RELEASE_11 RELEASE_11}. + * + * For {@linkplain * TypeMirror types} Xyz that may have more than one * kind, the visitXyz methods in this class delegate * to the visitXyzAsKind method corresponding to the @@ -75,7 +77,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor8 * @since 9 */ -@SupportedSourceVersion(RELEASE_10) +@SupportedSourceVersion(RELEASE_11) public class TypeKindVisitor9 extends TypeKindVisitor8 { /** * Constructor for concrete subclasses to call; uses {@code null} From e7ef03dce6a9aa00371743ee723882e85c15b435 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Tue, 1 May 2018 17:28:03 -0700 Subject: [PATCH 097/102] 8202130: [TESTBUG] Some appcds regression test cases fail with "Error: VM option 'PrintSystemDictionaryAtExit' is notproduct and is available only in debug version of VM" Removed the PrintSystemDictionaryAtExit vm option from the tests Reviewed-by: zgu --- .../jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java | 2 +- .../jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java | 4 ++-- .../runtime/appcds/jigsaw/modulepath/MainModuleOnly.java | 2 +- .../runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java index 260794e4402..33f756fd011 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java @@ -87,7 +87,7 @@ public class AddOpens { // the class in the modular jar in the -cp won't be archived. OutputAnalyzer output = TestCommon.createArchive( destJar.toString(), appClasses, - "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "-Xlog:class+load=trace", "--module-path", moduleDir.toString(), "-m", TEST_MODULE1); TestCommon.checkDump(output); diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java index e26d1c53b5e..2cc653e1eca 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java @@ -118,7 +118,7 @@ public class ExportModule { // the module in the --module-path OutputAnalyzer output = TestCommon.createArchive( appJar.toString(), appClasses, - "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "-Xlog:class+load=trace", "--module-path", moduleDir.toString(), "--add-modules", TEST_MODULE2, MAIN_CLASS); TestCommon.checkDump(output); @@ -142,7 +142,7 @@ public class ExportModule { // unnmaed. output = TestCommon.createArchive( appJar2.toString(), appClasses2, - "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "-Xlog:class+load=trace", "--module-path", moduleDir.toString(), "--add-modules", TEST_MODULE2, "--add-exports", "org.astro/org.astro=ALL-UNNAMED", diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java index 3809b9459ef..ee6c07ddf7b 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java @@ -88,7 +88,7 @@ public class MainModuleOnly { // the class in the modular jar in the -cp won't be archived. OutputAnalyzer output = TestCommon.createArchive( destJar.toString(), appClasses, - "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "-Xlog:class+load=trace", "--module-path", moduleDir.toString(), "-m", TEST_MODULE1); TestCommon.checkDump(output); diff --git a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java index 6fd7af4b350..990d7ed41d3 100644 --- a/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java +++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java @@ -132,7 +132,7 @@ public class ModulePathAndCP { String jars = subJar.toString() + System.getProperty("path.separator") + mainJar.toString(); output = TestCommon.createArchive( jars, appClasses, - "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "-Xlog:class+load=trace", "--module-path", moduleDir.toString(), "-m", MAIN_MODULE); TestCommon.checkDump(output); From d78303222bf81b806df8a32eb53b1e2cce228a96 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 2 May 2018 10:47:16 +0200 Subject: [PATCH 098/102] 8202425: [s390] C2: Wrong unsigned comparison with 0 Remove wrong node compU_reg_imm0. Other node is already available. Reviewed-by: shade, lucy --- src/hotspot/cpu/s390/s390.ad | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 4ebca5570ad..bfce705b368 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -8401,16 +8401,6 @@ instruct compU_reg_uimm(flagsReg cr, iRegI op1, uimmI op2) %{ ins_pipe(pipe_class_dummy); %} -instruct compU_reg_imm0(flagsReg cr, iRegI op1, immI_0 zero) %{ - match(Set cr (CmpU op1 zero)); - ins_cost(DEFAULT_COST_LOW); - size(2); - format %{ "LTR $op1,$op1\t # unsigned" %} - opcode(LTR_ZOPC); - ins_encode(z_rrform(op1, op1)); - ins_pipe(pipe_class_dummy); -%} - instruct compU_reg_mem(flagsReg cr, iRegI op1, memory op2)%{ match(Set cr (CmpU op1 (LoadI op2))); ins_cost(MEMORY_REF_COST); From 8e69e1b11fd5704e7055b5ceb3211a65e202e8c6 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 2 May 2018 02:36:17 -0700 Subject: [PATCH 099/102] 8202423: Small HTTP Client refresh Co-authored-by: Daniel Fuchs Co-authored-by: Michael McMahon Co-authored-by: Pavel Rappo Reviewed-by: chegar, dfuchs, michaelm, prappo --- .../internal/net/http/AsyncSSLConnection.java | 1 + .../net/http/AsyncSSLTunnelConnection.java | 1 + .../internal/net/http/Http1AsyncReceiver.java | 1 + .../jdk/internal/net/http/Http1Exchange.java | 18 +- .../jdk/internal/net/http/Http1Request.java | 4 +- .../jdk/internal/net/http/Http1Response.java | 11 +- .../internal/net/http/Http2ClientImpl.java | 21 +- .../internal/net/http/Http2Connection.java | 113 ++- .../jdk/internal/net/http/HttpClientImpl.java | 97 +- .../net/http/PlainHttpConnection.java | 28 +- .../jdk/internal/net/http/SocketTube.java | 220 ++++- .../classes/jdk/internal/net/http/Stream.java | 2 +- .../net/http/common/BufferSupplier.java | 67 ++ .../net/http/common/ByteBufferPool.java | 60 -- .../net/http/common/ByteBufferReference.java | 88 -- .../internal/net/http/common/DebugLogger.java | 42 +- .../internal/net/http/common/FlowTube.java | 2 + .../net/http/common/SSLFlowDelegate.java | 155 +++- .../jdk/internal/net/http/common/SSLTube.java | 11 +- .../net/http/common/SubscriberWrapper.java | 4 +- .../jdk/internal/net/http/common/Utils.java | 75 +- .../jdk/internal/net/http/hpack/Huffman.java | 669 +------------- .../internal/net/http/hpack/NaiveHuffman.java | 691 +++++++++++++++ .../internal/net/http/hpack/QuickHuffman.java | 826 ++++++++++++++++++ .../net/http/hpack/SimpleHeaderTable.java | 16 +- .../internal/net/http/hpack/StringReader.java | 2 +- .../internal/net/http/hpack/StringWriter.java | 4 +- .../BodyProcessorInputStreamTest.java | 4 +- .../DependentPromiseActionsTest.java | 22 +- .../net/httpclient/EscapedOctetsInURI.java | 3 + .../net/httpclient/HttpInputStreamTest.java | 4 +- .../net/httpclient/NonAsciiCharsInURI.java | 252 ++++++ test/jdk/java/net/httpclient/ProxyServer.java | 28 +- .../java/net/httpclient/RetryWithCookie.java | 2 + .../jdk/java/net/httpclient/SmallTimeout.java | 26 +- .../java/net/httpclient/TimeoutOrdering.java | 18 +- .../net/http/hpack/CircularBufferTest.java | 11 +- .../internal/net/http/hpack/DecoderTest.java | 46 +- .../internal/net/http/hpack/HuffmanTest.java | 30 +- .../http2/server/Http2TestServer.java | 34 +- .../websocket/DummyWebSocketServer.java | 1 + .../websocket/PendingBinaryPingClose.java | 6 +- .../websocket/PendingBinaryPongClose.java | 6 +- .../websocket/PendingPingBinaryClose.java | 6 +- .../websocket/PendingPingTextClose.java | 6 +- .../websocket/PendingPongBinaryClose.java | 6 +- .../websocket/PendingPongTextClose.java | 4 +- .../websocket/PendingTextPingClose.java | 6 +- .../websocket/PendingTextPongClose.java | 6 +- .../net/httpclient/websocket/SendTest.java | 7 +- .../websocket/WSHandshakeExceptionTest.java | 3 + .../websocket/WebSocketExtendedTest.java | 14 +- .../httpclient/websocket/WebSocketTest.java | 20 +- 53 files changed, 2770 insertions(+), 1030 deletions(-) create mode 100644 src/java.net.http/share/classes/jdk/internal/net/http/common/BufferSupplier.java delete mode 100644 src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferPool.java delete mode 100644 src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferReference.java create mode 100644 src/java.net.http/share/classes/jdk/internal/net/http/hpack/NaiveHuffman.java create mode 100644 src/java.net.http/share/classes/jdk/internal/net/http/hpack/QuickHuffman.java create mode 100644 test/jdk/java/net/httpclient/NonAsciiCharsInURI.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java index 79447439261..36cf52ca526 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java @@ -61,6 +61,7 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection { // create the SSLTube wrapping the SocketTube, with the given engine flow = new SSLTube(engine, client().theExecutor(), + client().getSSLBufferSupplier()::recycle, plainConnection.getConnectionFlow()); return null; } ); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java index fb9b385571e..8d76434fc98 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java @@ -65,6 +65,7 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection { // create the SSLTube wrapping the SocketTube, with the given engine flow = new SSLTube(engine, client().theExecutor(), + client().getSSLBufferSupplier()::recycle, plainConnection.getConnectionFlow()); return null;} ); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1AsyncReceiver.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1AsyncReceiver.java index 010b9243115..41e023ee095 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1AsyncReceiver.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1AsyncReceiver.java @@ -356,6 +356,7 @@ class Http1AsyncReceiver { // be left over in the stream. try { setRetryOnError(false); + pending.close(null); onReadError(new IOException("subscription cancelled")); unsubscribe(pending); } finally { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java index 50230b1ab0b..8b9493cae0b 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java @@ -259,8 +259,19 @@ class Http1Exchange extends ExchangeImpl { if (!connection.connected()) { if (debug.on()) debug.log("initiating connect async"); connectCF = connection.connectAsync(); + Throwable cancelled; synchronized (lock) { - operations.add(connectCF); + if ((cancelled = failed) == null) { + operations.add(connectCF); + } + } + if (cancelled != null) { + if (client.isSelectorThread()) { + executor.execute(() -> + connectCF.completeExceptionally(cancelled)); + } else { + connectCF.completeExceptionally(cancelled); + } } } else { connectCF = new MinimalFuture<>(); @@ -403,6 +414,9 @@ class Http1Exchange extends ExchangeImpl { if ((error = failed) == null) { failed = error = cause; } + if (debug.on()) { + debug.log(request.uri() + ": " + error); + } if (requestAction != null && requestAction.finished() && response != null && response.finished()) { return; @@ -447,7 +461,7 @@ class Http1Exchange extends ExchangeImpl { exec.execute(() -> { if (cf.completeExceptionally(x)) { if (debug.on()) - debug.log("completed cf with %s", (Object) x); + debug.log("%s: completed cf with %s", request.uri(), x); } }); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java index 5f84825b7f1..0c765b6f85d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Request.java @@ -200,9 +200,9 @@ class Http1Request { query = ""; } if (query.equals("")) { - return path; + return Utils.encode(path); } else { - return path + "?" + query; + return Utils.encode(path + "?" + query); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java index bd50c4465f3..b8240a8ac9b 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Response.java @@ -375,12 +375,17 @@ class Http1Response { (t) -> { try { if (t != null) { - subscriber.onError(t); - connection.close(); - cf.completeExceptionally(t); + try { + subscriber.onError(t); + } finally { + cf.completeExceptionally(t); + } } } finally { bodyReader.onComplete(t); + if (t != null) { + connection.close(); + } } })); CompletableFuture bodyReaderCF = bodyReader.completion(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java index ed7867cfece..00612296f7c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java @@ -95,10 +95,10 @@ class Http2ClientImpl { synchronized (this) { Http2Connection connection = connections.get(key); if (connection != null) { - if (connection.closed) { + if (connection.closed || !connection.reserveStream(true)) { if (debug.on()) - debug.log("removing found closed connection: %s", connection); - connections.remove(key); + debug.log("removing found closed or closing connection: %s", connection); + deleteConnection(connection); } else { // fast path if connection already exists if (debug.on()) @@ -138,9 +138,9 @@ class Http2ClientImpl { */ boolean offerConnection(Http2Connection c) { if (debug.on()) debug.log("offering to the connection pool: %s", c); - if (c.closed) { + if (c.closed || c.finalStream()) { if (debug.on()) - debug.log("skipping offered closed connection: %s", c); + debug.log("skipping offered closed or closing connection: %s", c); return false; } @@ -148,7 +148,7 @@ class Http2ClientImpl { synchronized(this) { Http2Connection c1 = connections.putIfAbsent(key, c); if (c1 != null) { - c.setSingleStream(true); + c.setFinalStream(); if (debug.on()) debug.log("existing entry in connection pool for %s", key); return false; @@ -163,9 +163,12 @@ class Http2ClientImpl { if (debug.on()) debug.log("removing from the connection pool: %s", c); synchronized (this) { - connections.remove(c.key()); - if (debug.on()) - debug.log("removed from the connection pool: %s", c); + Http2Connection c1 = connections.get(c.key()); + if (c1 != null && c1.equals(c)) { + connections.remove(c.key()); + if (debug.on()) + debug.log("removed from the connection pool: %s", c); + } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 40cf3e4e8fe..b5a64e6f614 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -121,33 +121,66 @@ class Http2Connection { Utils.getHpackLogger(this::dbgString, Utils.DEBUG_HPACK); static final ByteBuffer EMPTY_TRIGGER = ByteBuffer.allocate(0); - private boolean singleStream; // used only for stream 1, then closed + static private final int MAX_CLIENT_STREAM_ID = Integer.MAX_VALUE; // 2147483647 + static private final int MAX_SERVER_STREAM_ID = Integer.MAX_VALUE - 1; // 2147483646 + + /** + * Flag set when no more streams to be opened on this connection. + * Two cases where it is used. + * + * 1. Two connections to the same server were opened concurrently, in which + * case one of them will be put in the cache, and the second will expire + * when all its opened streams (which usually should be a single client + * stream + possibly some additional push-promise server streams) complete. + * 2. A cached connection reaches its maximum number of streams (~ 2^31-1) + * either server / or client allocated, in which case it will be taken + * out of the cache - allowing a new connection to replace it. It will + * expire when all its still open streams (which could be many) eventually + * complete. + */ + private boolean finalStream; /* - * ByteBuffer pooling strategy for HTTP/2 protocol: + * ByteBuffer pooling strategy for HTTP/2 protocol. * * In general there are 4 points where ByteBuffers are used: - * - incoming/outgoing frames from/to ByteBuffers plus incoming/outgoing encrypted data - * in case of SSL connection. + * - incoming/outgoing frames from/to ByteBuffers plus incoming/outgoing + * encrypted data in case of SSL connection. * * 1. Outgoing frames encoded to ByteBuffers. - * Outgoing ByteBuffers are created with requited size and frequently small (except DataFrames, etc) - * At this place no pools at all. All outgoing buffers should be collected by GC. + * + * Outgoing ByteBuffers are created with required size and frequently + * small (except DataFrames, etc). At this place no pools at all. All + * outgoing buffers should eventually be collected by GC. * * 2. Incoming ByteBuffers (decoded to frames). - * Here, total elimination of BB pool is not a good idea. - * We don't know how many bytes we will receive through network. - * So here we allocate buffer of reasonable size. The following life of the BB: - * - If all frames decoded from the BB are other than DataFrame and HeaderFrame (and HeaderFrame subclasses) - * BB is returned to pool, - * - If we decoded DataFrame from the BB. In that case DataFrame refers to subbuffer obtained by slice() method. - * Such BB is never returned to pool and will be GCed. - * - If we decoded HeadersFrame from the BB. Then header decoding is performed inside processFrame method and - * the buffer could be release to pool. * - * 3. SLL encrypted buffers. Here another pool was introduced and all net buffers are to/from the pool, - * because of we can't predict size encrypted packets. + * Here, total elimination of BB pool is not a good idea. + * We don't know how many bytes we will receive through network. * + * A possible future improvement ( currently not implemented ): + * Allocate buffers of reasonable size. The following life of the BB: + * - If all frames decoded from the BB are other than DataFrame and + * HeaderFrame (and HeaderFrame subclasses) BB is returned to pool, + * - If a DataFrame is decoded from the BB. In that case DataFrame refers + * to sub-buffer obtained by slice(). Such a BB is never returned to the + * pool and will eventually be GC'ed. + * - If a HeadersFrame is decoded from the BB. Then header decoding is + * performed inside processFrame method and the buffer could be release + * back to pool. + * + * 3. SSL encrypted buffers ( received ). + * + * The current implementation recycles encrypted buffers read from the + * channel. The pool of buffers has a maximum size of 3, SocketTube.MAX_BUFFERS, + * direct buffers which are shared by all connections on a given client. + * The pool is used by all SSL connections - whether HTTP/1.1 or HTTP/2, + * but only for SSL encrypted buffers that circulate between the SocketTube + * Publisher and the SSLFlowDelegate Reader. Limiting the pool to this + * particular segment allows the use of direct buffers, thus avoiding any + * additional copy in the NIO socket channel implementation. See + * HttpClientImpl.SSLDirectBufferSupplier, SocketTube.SSLDirectBufferSource, + * and SSLTube.recycler. */ @@ -220,6 +253,12 @@ class Http2Connection { private final Map> streams = new ConcurrentHashMap<>(); private int nextstreamid; private int nextPushStream = 2; + // actual stream ids are not allocated until the Headers frame is ready + // to be sent. The following two fields are updated as soon as a stream + // is created and assigned to a connection. They are checked before + // assigning a stream to a connection. + private int lastReservedClientStreamid = 1; + private int lastReservedServerStreamid = 0; private final Encoder hpackOut; private final Decoder hpackIn; final SettingsFrame clientSettings; @@ -365,6 +404,29 @@ class Http2Connection { return client2.client(); } + // call these before assigning a request/stream to a connection + // if false returned then a new Http2Connection is required + // if true, the the stream may be assigned to this connection + synchronized boolean reserveStream(boolean clientInitiated) { + if (finalStream) { + return false; + } + if (clientInitiated && (lastReservedClientStreamid + 2) >= MAX_CLIENT_STREAM_ID) { + setFinalStream(); + client2.deleteConnection(this); + return false; + } else if (!clientInitiated && (lastReservedServerStreamid + 2) >= MAX_SERVER_STREAM_ID) { + setFinalStream(); + client2.deleteConnection(this); + return false; + } + if (clientInitiated) + lastReservedClientStreamid+=2; + else + lastReservedServerStreamid+=2; + return true; + } + /** * Throws an IOException if h2 was not negotiated */ @@ -414,12 +476,16 @@ class Http2Connection { .thenCompose(checkAlpnCF); } - synchronized boolean singleStream() { - return singleStream; + synchronized boolean finalStream() { + return finalStream; } - synchronized void setSingleStream(boolean use) { - singleStream = use; + /** + * Mark this connection so no more streams created on it and it will close when + * all are complete. + */ + synchronized void setFinalStream() { + finalStream = true; } static String keyFor(HttpConnection connection) { @@ -693,6 +759,9 @@ class Http2Connection { if (promisedStreamid != nextPushStream) { resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR); return; + } else if (!reserveStream(false)) { + resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM); + return; } else { nextPushStream += 2; } @@ -752,7 +821,7 @@ class Http2Connection { // corresponding entry in the window controller. windowController.removeStream(streamid); } - if (singleStream() && streams.isEmpty()) { + if (finalStream() && streams.isEmpty()) { // should be only 1 stream, but there might be more if server push close(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 06258e4b028..0597c389429 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -28,12 +28,12 @@ package jdk.internal.net.http; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; import java.io.IOException; -import java.lang.System.Logger.Level; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.net.Authenticator; import java.net.CookieHandler; import java.net.ProxySelector; +import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; @@ -47,7 +47,6 @@ import java.security.PrivilegedAction; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; @@ -57,6 +56,7 @@ import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -70,6 +70,7 @@ import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.PushPromiseHandler; import java.net.http.WebSocket; +import jdk.internal.net.http.common.BufferSupplier; import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.Pair; @@ -138,6 +139,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { private final long id; private final String dbgTag; + // The SSL DirectBuffer Supplier provides the ability to recycle + // buffers used between the socket reader and the SSLEngine, or + // more precisely between the SocketTube publisher and the + // SSLFlowDelegate reader. + private final SSLDirectBufferSupplier sslBufferSupplier + = new SSLDirectBufferSupplier(this); + // This reference is used to keep track of the facade HttpClient // that was returned to the application code. // It makes it possible to know when the application no longer @@ -1160,7 +1168,90 @@ final class HttpClientImpl extends HttpClient implements Trackable { // used for the connection window int getReceiveBufferSize() { return Utils.getIntegerNetProperty( - "jdk.httpclient.receiveBufferSize", 2 * 1024 * 1024 + "jdk.httpclient.receiveBufferSize", + 0 // only set the size if > 0 ); } + + // Optimization for reading SSL encrypted data + // -------------------------------------------- + + // Returns a BufferSupplier that can be used for reading + // encrypted bytes of the channel. These buffers can then + // be recycled by the SSLFlowDelegate::Reader after their + // content has been copied in the SSLFlowDelegate::Reader + // readBuf. + // Because allocating, reading, copying, and recycling + // all happen in the SelectorManager thread, + // then this BufferSupplier can be shared between all + // the SSL connections managed by this client. + BufferSupplier getSSLBufferSupplier() { + return sslBufferSupplier; + } + + // An implementation of BufferSupplier that manages a pool of + // maximum 3 direct byte buffers (SocketTube.MAX_BUFFERS) that + // are used for reading encrypted bytes off the channel before + // copying and subsequent unwrapping. + private static final class SSLDirectBufferSupplier implements BufferSupplier { + private static final int POOL_SIZE = SocketTube.MAX_BUFFERS; + private final ByteBuffer[] pool = new ByteBuffer[POOL_SIZE]; + private final HttpClientImpl client; + private final Logger debug; + private int tail, count; // no need for volatile: only accessed in SM thread. + + SSLDirectBufferSupplier(HttpClientImpl client) { + this.client = Objects.requireNonNull(client); + this.debug = client.debug; + } + + // Gets a buffer from the pool, or allocates a new one if needed. + @Override + public ByteBuffer get() { + assert client.isSelectorThread(); + assert tail <= POOL_SIZE : "allocate tail is " + tail; + ByteBuffer buf; + if (tail == 0) { + if (debug.on()) { + // should not appear more than SocketTube.MAX_BUFFERS + debug.log("ByteBuffer.allocateDirect(%d)", Utils.BUFSIZE); + } + assert count++ < POOL_SIZE : "trying to allocate more than " + + POOL_SIZE + " buffers"; + buf = ByteBuffer.allocateDirect(Utils.BUFSIZE); + } else { + assert tail > 0 : "non positive tail value: " + tail; + tail--; + buf = pool[tail]; + pool[tail] = null; + } + assert buf.isDirect(); + assert buf.position() == 0; + assert buf.hasRemaining(); + assert buf.limit() == Utils.BUFSIZE; + assert tail < POOL_SIZE; + assert tail >= 0; + return buf; + } + + // Returns the given buffer to the pool. + @Override + public void recycle(ByteBuffer buffer) { + assert client.isSelectorThread(); + assert buffer.isDirect(); + assert !buffer.hasRemaining(); + assert tail < POOL_SIZE : "recycle tail is " + tail; + assert tail >= 0; + buffer.position(0); + buffer.limit(buffer.capacity()); + // don't fail if assertions are off. we have asserted above. + if (tail < POOL_SIZE) { + pool[tail] = buffer; + tail++; + } + assert tail <= POOL_SIZE; + assert tail > 0; + } + } + } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java index 4d01c103eb1..d6b4c64df9e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java @@ -145,31 +145,39 @@ class PlainHttpConnection extends HttpConnection { try { this.chan = SocketChannel.open(); chan.configureBlocking(false); - int bufsize = client.getReceiveBufferSize(); - if (!trySetReceiveBufferSize(bufsize)) { - trySetReceiveBufferSize(256*1024); + trySetReceiveBufferSize(client.getReceiveBufferSize()); + if (debug.on()) { + int bufsize = getInitialBufferSize(); + debug.log("Initial receive buffer size is: %d", bufsize); } chan.setOption(StandardSocketOptions.TCP_NODELAY, true); - // wrap the connected channel in a Tube for async reading and writing + // wrap the channel in a Tube for async reading and writing tube = new SocketTube(client(), chan, Utils::getBuffer); } catch (IOException e) { throw new InternalError(e); } } - private boolean trySetReceiveBufferSize(int bufsize) { + private int getInitialBufferSize() { try { - chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize); + return chan.getOption(StandardSocketOptions.SO_RCVBUF); + } catch(IOException x) { if (debug.on()) - debug.log("Receive buffer size is %s", - chan.getOption(StandardSocketOptions.SO_RCVBUF)); - return true; + debug.log("Failed to get initial receive buffer size on %s", chan); + } + return 0; + } + + private void trySetReceiveBufferSize(int bufsize) { + try { + if (bufsize > 0) { + chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize); + } } catch(IOException x) { if (debug.on()) debug.log("Failed to set receive buffer size to %d on %s", bufsize, chan); } - return false; } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java index bb348245ba4..a680dcd56c7 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java @@ -26,7 +26,6 @@ package jdk.internal.net.http; import java.io.IOException; -import java.lang.System.Logger.Level; import java.nio.ByteBuffer; import java.util.List; import java.util.Objects; @@ -39,6 +38,7 @@ import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.function.Consumer; import java.util.function.Supplier; +import jdk.internal.net.http.common.BufferSupplier; import jdk.internal.net.http.common.Demand; import jdk.internal.net.http.common.FlowTube; import jdk.internal.net.http.common.Logger; @@ -59,7 +59,7 @@ final class SocketTube implements FlowTube { private final HttpClientImpl client; private final SocketChannel channel; - private final Supplier buffersSource; + private final SliceBufferSource sliceBuffersSource; private final Object lock = new Object(); private final AtomicReference errorRef = new AtomicReference<>(); private final InternalReadPublisher readPublisher; @@ -67,10 +67,11 @@ final class SocketTube implements FlowTube { private final long id = IDS.incrementAndGet(); public SocketTube(HttpClientImpl client, SocketChannel channel, - Supplier buffersSource) { + Supplier buffersFactory) { this.client = client; this.channel = channel; - this.buffersSource = buffersSource; + this.sliceBuffersSource = new SliceBufferSource(buffersFactory); + this.readPublisher = new InternalReadPublisher(); this.writeSubscriber = new InternalWriteSubscriber(); } @@ -564,6 +565,7 @@ final class SocketTube implements FlowTube { final InternalReadSubscription impl; final TubeSubscriber subscriber; final AtomicReference errorRef = new AtomicReference<>(); + final BufferSource bufferSource; volatile boolean subscribed; volatile boolean cancelled; volatile boolean completed; @@ -571,6 +573,9 @@ final class SocketTube implements FlowTube { public ReadSubscription(InternalReadSubscription impl, TubeSubscriber subscriber) { this.impl = impl; + this.bufferSource = subscriber.supportsRecycling() + ? new SSLDirectBufferSource(client) + : SocketTube.this.sliceBuffersSource; this.subscriber = subscriber; } @@ -779,7 +784,7 @@ final class SocketTube implements FlowTube { if (demand.tryDecrement()) { // we have demand. try { - List bytes = readAvailable(); + List bytes = readAvailable(current.bufferSource); if (bytes == EOF) { if (!completed) { if (debug.on()) debug.log("got read EOF"); @@ -905,6 +910,180 @@ final class SocketTube implements FlowTube { } } + // ===================================================================== // + // Buffer Management // + // ===================================================================== // + + // This interface is used by readAvailable(BufferSource); + public interface BufferSource { + /** + * Returns a buffer to read data from the socket. + * + * @implNote + * Different implementation can have different strategies, as to + * which kind of buffer to return, or whether to return the same + * buffer. The only constraints are that: + * a. the buffer returned must not be null + * b. the buffer position indicates where to start reading + * c. the buffer limit indicates where to stop reading. + * d. the buffer is 'free' - that is - it is not used + * or retained by anybody else + * + * @return A buffer to read data from the socket. + */ + ByteBuffer getBuffer(); + + /** + * Appends the read-data in {@code buffer} to the list of buffer to + * be sent downstream to the subscriber. May return a new + * list, or append to the given list. + * + * @implNote + * Different implementation can have different strategies, but + * must obviously be consistent with the implementation of the + * getBuffer() method. For instance, an implementation could + * decide to add the buffer to the list and return a new buffer + * next time getBuffer() is called, or could decide to add a buffer + * slice to the list and return the same buffer (if remaining + * space is available) next time getBuffer() is called. + * + * @param list The list before adding the data. Can be null. + * @param buffer The buffer containing the data to add to the list. + * @param start The start position at which data were read. + * The current buffer position indicates the end. + * @return A possibly new list where a buffer containing the + * data read from the socket has been added. + */ + List append(List list, ByteBuffer buffer, int start); + + /** + * Returns the given unused {@code buffer}, previously obtained from + * {@code getBuffer}. + * + * @implNote This method can be used, if necessary, to return + * the unused buffer to the pull. + * + * @param buffer The unused buffer. + */ + default void returnUnused(ByteBuffer buffer) { } + } + + // An implementation of BufferSource used for unencrypted data. + // This buffer source uses heap buffers and avoids wasting memory + // by forwarding read-only buffer slices downstream. + // Buffers allocated through this source are simply GC'ed when + // they are no longer referenced. + private static final class SliceBufferSource implements BufferSource { + private final Supplier factory; + private volatile ByteBuffer current; + + public SliceBufferSource() { + this(Utils::getBuffer); + } + public SliceBufferSource(Supplier factory) { + this.factory = Objects.requireNonNull(factory); + } + + // Reuses the same buffer if some space remains available. + // Otherwise, returns a new heap buffer. + @Override + public final ByteBuffer getBuffer() { + ByteBuffer buf = current; + buf = (buf == null || !buf.hasRemaining()) + ? (current = factory.get()) : buf; + assert buf.hasRemaining(); + return buf; + } + + // Adds a read-only slice to the list, potentially returning a + // new list with that slice at the end. + @Override + public final List append(List list, ByteBuffer buf, int start) { + // creates a slice to add to the list + int limit = buf.limit(); + buf.limit(buf.position()); + buf.position(start); + ByteBuffer slice = buf.slice(); + + // restore buffer state to what it was before creating the slice + buf.position(buf.limit()); + buf.limit(limit); + + // add the buffer to the list + return SocketTube.listOf(list, slice.asReadOnlyBuffer()); + } + } + + + // An implementation of BufferSource used for encrypted data. + // This buffer source uses direct byte buffers that will be + // recycled by the SocketTube subscriber. + // + private static final class SSLDirectBufferSource implements BufferSource { + private final BufferSupplier factory; + private final HttpClientImpl client; + private ByteBuffer current; + + public SSLDirectBufferSource(HttpClientImpl client) { + this.client = Objects.requireNonNull(client); + this.factory = Objects.requireNonNull(client.getSSLBufferSupplier()); + } + + // Obtains a 'free' byte buffer from the pool, or returns + // the same buffer if nothing was read at the previous cycle. + // The subscriber will be responsible for recycling this + // buffer into the pool (see SSLFlowDelegate.Reader) + @Override + public final ByteBuffer getBuffer() { + assert client.isSelectorThread(); + ByteBuffer buf = current; + if (buf == null) { + buf = current = factory.get(); + } + assert buf.hasRemaining(); + assert buf.position() == 0; + return buf; + } + + // Adds the buffer to the list. The buffer will be later returned to the + // pool by the subscriber (see SSLFlowDelegate.Reader). + // The next buffer returned by getBuffer() will be obtained from the + // pool. It might be the same buffer or another one. + // Because socket tube can read up to MAX_BUFFERS = 3 buffers, and because + // recycling will happen in the flow before onNext returns, then the + // pool can not grow larger than MAX_BUFFERS = 3 buffers, even though + // it's shared by all SSL connections opened on that client. + @Override + public final List append(List list, ByteBuffer buf, int start) { + assert client.isSelectorThread(); + assert buf.isDirect(); + assert start == 0; + assert current == buf; + current = null; + buf.limit(buf.position()); + buf.position(start); + // add the buffer to the list + return SocketTube.listOf(list, buf); + } + + @Override + public void returnUnused(ByteBuffer buffer) { + // if current is null, then the buffer will have been added to the + // list, through append. Otherwise, current is not null, and needs + // to be returned to prevent the buffer supplier pool from growing + // to more than MAX_BUFFERS. + assert buffer == current; + ByteBuffer buf = current; + if (buf != null) { + assert buf.position() == 0; + current = null; + // the supplier assert if buf has remaining + buf.limit(buf.position()); + factory.recycle(buf); + } + } + } + // ===================================================================== // // Socket Channel Read/Write // // ===================================================================== // @@ -918,11 +1097,8 @@ final class SocketTube implements FlowTube { // is inserted into the returned buffer list, and if the current buffer // has remaining space, that space will be used to read more data when // the channel becomes readable again. - private volatile ByteBuffer current; - private List readAvailable() throws IOException { - ByteBuffer buf = current; - buf = (buf == null || !buf.hasRemaining()) - ? (current = buffersSource.get()) : buf; + private List readAvailable(BufferSource buffersSource) throws IOException { + ByteBuffer buf = buffersSource.getBuffer(); assert buf.hasRemaining(); int read; @@ -936,6 +1112,9 @@ final class SocketTube implements FlowTube { } } catch (IOException x) { if (buf.position() == pos && list == null) { + // make sure that the buffer source will recycle + // 'buf' if needed + buffersSource.returnUnused(buf); // no bytes have been read, just throw... throw x; } else { @@ -951,6 +1130,7 @@ final class SocketTube implements FlowTube { // returned if read == -1. If some data has already been read, // then it must be returned. -1 will be returned next time // the caller attempts to read something. + buffersSource.returnUnused(buf); if (list == null) { // nothing read - list was null - return EOF or NOTHING list = read == -1 ? EOF : NOTHING; @@ -960,39 +1140,27 @@ final class SocketTube implements FlowTube { // check whether this buffer has still some free space available. // if so, we will keep it for the next round. - final boolean hasRemaining = buf.hasRemaining(); + list = buffersSource.append(list, buf, pos); - // creates a slice to add to the list - int limit = buf.limit(); - buf.limit(buf.position()); - buf.position(pos); - ByteBuffer slice = buf.slice(); - - // restore buffer state to what it was before creating the slice - buf.position(buf.limit()); - buf.limit(limit); - - // add the buffer to the list - list = addToList(list, slice.asReadOnlyBuffer()); if (read <= 0 || list.size() == MAX_BUFFERS) { break; } - buf = hasRemaining ? buf : (current = buffersSource.get()); + buf = buffersSource.getBuffer(); pos = buf.position(); assert buf.hasRemaining(); } return list; } - private List addToList(List list, T item) { + private static List listOf(List list, T item) { int size = list == null ? 0 : list.size(); switch (size) { case 0: return List.of(item); case 1: return List.of(list.get(0), item); case 2: return List.of(list.get(0), list.get(1), item); default: // slow path if MAX_BUFFERS > 3 - ArrayList res = new ArrayList<>(list); + List res = list instanceof ArrayList ? list : new ArrayList<>(list); res.add(item); return res; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index b90b8d96d2c..0daede7be2e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -614,7 +614,7 @@ class Stream extends ExchangeImpl { if (query != null) { path += "?" + query; } - hdrs.setHeader(":path", path); + hdrs.setHeader(":path", Utils.encode(path)); } HttpHeadersImpl getRequestPseudoHeaders() { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/BufferSupplier.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/BufferSupplier.java new file mode 100644 index 00000000000..33dbe810923 --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/BufferSupplier.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.net.http.common; + +import java.nio.ByteBuffer; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.function.Supplier; + +/** + * This interface allows to recycle buffers used for SSL decryption. + * Buffers that are used for reading SSL encrypted data are typically + * very short lived, as it is necessary to aggregate their content + * before calling SSLEngine::unwrap. + * Because both reading and copying happen in the SelectorManager + * thread, then it makes it possible to pool these buffers and + * recycle them for the next socket read, instead of simply + * letting them be GC'ed. That also makes it possible to use + * direct byte buffers, and avoid another layer of copying by + * the SocketChannel implementation. + * + * The HttpClientImpl has an implementation of this interface + * that allows to reuse the same 3 direct buffers for reading + * off SSL encrypted data from the socket. + * The BufferSupplier::get method is called by SocketTube + * (see SocketTube.SSLDirectBufferSource) and BufferSupplier::recycle + * is called by SSLFlowDelegate.Reader. + **/ +public interface BufferSupplier extends Supplier { + /** + * Returns a buffer to read encrypted data off the socket. + * @return a buffer to read encrypted data off the socket. + */ + ByteBuffer get(); + + /** + * Returns a buffer to the pool. + * + * @param buffer This must be a buffer previously obtained + * by calling BufferSupplier::get. The caller must + * not touch the buffer after returning it to + * the pool. + */ + void recycle(ByteBuffer buffer); +} + diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferPool.java deleted file mode 100644 index 08f1a5e4f18..00000000000 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferPool.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.net.http.common; - -import java.nio.ByteBuffer; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * The class provides reuse of ByteBuffers. - * It is supposed that all requested buffers have the same size for a long period of time. - * That is why there is no any logic splitting buffers into different buckets (by size). It's unnecessary. - * - * At the same moment it is allowed to change requested buffers size (all smaller buffers will be discarded). - * It may be needed for example, if after rehandshaking netPacketBufferSize was changed. - */ -public class ByteBufferPool { - - private final java.util.Queue pool = new ConcurrentLinkedQueue<>(); - - public ByteBufferPool() { - } - - public ByteBufferReference get(int size) { - ByteBuffer buffer; - while ((buffer = pool.poll()) != null) { - if (buffer.capacity() >= size) { - return ByteBufferReference.of(buffer, this); - } - } - return ByteBufferReference.of(ByteBuffer.allocate(size), this); - } - - public void release(ByteBuffer buffer) { - buffer.clear(); - pool.offer(buffer); - } - -} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferReference.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferReference.java deleted file mode 100644 index 4e5a61b4f6f..00000000000 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/ByteBufferReference.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.net.http.common; - -import java.nio.ByteBuffer; -import java.util.Objects; -import java.util.function.Supplier; - -public class ByteBufferReference implements Supplier { - - private ByteBuffer buffer; - private final ByteBufferPool pool; - - public static ByteBufferReference of(ByteBuffer buffer) { - return of(buffer, null); - } - - public static ByteBufferReference of(ByteBuffer buffer, ByteBufferPool pool) { - Objects.requireNonNull(buffer); - return new ByteBufferReference(buffer, pool); - } - - public static ByteBuffer[] toBuffers(ByteBufferReference... refs) { - ByteBuffer[] bufs = new ByteBuffer[refs.length]; - for (int i = 0; i < refs.length; i++) { - bufs[i] = refs[i].get(); - } - return bufs; - } - - public static ByteBufferReference[] toReferences(ByteBuffer... buffers) { - ByteBufferReference[] refs = new ByteBufferReference[buffers.length]; - for (int i = 0; i < buffers.length; i++) { - refs[i] = of(buffers[i]); - } - return refs; - } - - - public static void clear(ByteBufferReference[] refs) { - for(ByteBufferReference ref : refs) { - ref.clear(); - } - } - - private ByteBufferReference(ByteBuffer buffer, ByteBufferPool pool) { - this.buffer = buffer; - this.pool = pool; - } - - @Override - public ByteBuffer get() { - ByteBuffer buf = this.buffer; - assert buf!=null : "getting ByteBuffer after clearance"; - return buf; - } - - public void clear() { - ByteBuffer buf = this.buffer; - assert buf!=null : "double ByteBuffer clearance"; - this.buffer = null; - if (pool != null) { - pool.release(buf); - } - } -} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/DebugLogger.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/DebugLogger.java index bed4423a9d1..57358e33bcc 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/DebugLogger.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/DebugLogger.java @@ -52,6 +52,12 @@ final class DebugLogger implements Logger { final static System.Logger HTTP = System.getLogger(HTTP_NAME); final static System.Logger WS = System.getLogger(WS_NAME); final static System.Logger HPACK = System.getLogger(HPACK_NAME); + private static final DebugLogger NO_HTTP_LOGGER = + new DebugLogger(HTTP, "HTTP"::toString, Level.OFF, Level.OFF); + private static final DebugLogger NO_WS_LOGGER = + new DebugLogger(HTTP, "WS"::toString, Level.OFF, Level.OFF); + private static final DebugLogger NO_HPACK_LOGGER = + new DebugLogger(HTTP, "HPACK"::toString, Level.OFF, Level.OFF); final static long START_NANOS = System.nanoTime(); private final Supplier dbgTag; @@ -112,11 +118,7 @@ final class DebugLogger implements Logger { } private boolean isEnabled(Level level) { - if (level == Level.OFF) return false; - int severity = level.getSeverity(); - return severity >= errLevel.getSeverity() - || severity >= outLevel.getSeverity() - || logger.isLoggable(level); + return levelEnabledFor(level, outLevel, errLevel, logger); } @Override @@ -124,6 +126,15 @@ final class DebugLogger implements Logger { return debugOn; } + static boolean levelEnabledFor(Level level, Level outLevel, Level errLevel, + System.Logger logger) { + if (level == Level.OFF) return false; + int severity = level.getSeverity(); + return severity >= errLevel.getSeverity() + || severity >= outLevel.getSeverity() + || logger.isLoggable(level); + } + @Override public boolean isLoggable(Level level) { // fast path, we assume these guys never change. @@ -251,18 +262,33 @@ final class DebugLogger implements Logger { public static DebugLogger createHttpLogger(Supplier dbgTag, Level outLevel, Level errLevel) { - return new DebugLogger(HTTP, dbgTag, outLevel, errLevel); + if (levelEnabledFor(Level.DEBUG, outLevel, errLevel, HTTP)) { + return new DebugLogger(HTTP, dbgTag, outLevel, errLevel); + } else { + // return a shared instance if debug logging is not enabled. + return NO_HTTP_LOGGER; + } } public static DebugLogger createWebSocketLogger(Supplier dbgTag, Level outLevel, Level errLevel) { - return new DebugLogger(WS, dbgTag, outLevel, errLevel); + if (levelEnabledFor(Level.DEBUG, outLevel, errLevel, WS)) { + return new DebugLogger(WS, dbgTag, outLevel, errLevel); + } else { + // return a shared instance if logging is not enabled. + return NO_WS_LOGGER; + } } public static DebugLogger createHpackLogger(Supplier dbgTag, Level outLevel, Level errLevel) { - return new DebugLogger(HPACK, dbgTag, outLevel, errLevel); + if (levelEnabledFor(Level.DEBUG, outLevel, errLevel, HPACK)) { + return new DebugLogger(HPACK, dbgTag, outLevel, errLevel); + } else { + // return a shared instance if logging is not enabled. + return NO_HPACK_LOGGER; + } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/FlowTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/FlowTube.java index 9187fa2e3e4..f079f400c12 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/FlowTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/FlowTube.java @@ -63,6 +63,8 @@ public interface FlowTube extends */ default void dropSubscription() { } + default boolean supportsRecycling() { return false; } + } /** diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java index f9b14832e00..40ac2deae52 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java @@ -33,7 +33,6 @@ import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; import javax.net.ssl.SSLException; import java.io.IOException; -import java.lang.System.Logger.Level; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -46,6 +45,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; /** * Implements SSL using two SubscriberWrappers. @@ -97,6 +97,7 @@ public class SSLFlowDelegate { volatile boolean close_notify_received; final CompletableFuture readerCF; final CompletableFuture writerCF; + final Consumer recycler; static AtomicInteger scount = new AtomicInteger(1); final int id; @@ -110,8 +111,23 @@ public class SSLFlowDelegate { Subscriber> downReader, Subscriber> downWriter) { + this(engine, exec, null, downReader, downWriter); + } + + /** + * Creates an SSLFlowDelegate fed from two Flow.Subscribers. Each + * Flow.Subscriber requires an associated {@link CompletableFuture} + * for errors that need to be signaled from downstream to upstream. + */ + public SSLFlowDelegate(SSLEngine engine, + Executor exec, + Consumer recycler, + Subscriber> downReader, + Subscriber> downWriter) + { this.id = scount.getAndIncrement(); this.tubeName = String.valueOf(downWriter); + this.recycler = recycler; this.reader = new Reader(); this.writer = new Writer(); this.engine = engine; @@ -181,9 +197,11 @@ public class SSLFlowDelegate { sb.append("SSL: id ").append(id); sb.append(" HS state: " + states(handshakeState)); sb.append(" Engine state: " + engine.getHandshakeStatus().toString()); - sb.append(" LL : "); - for (String s: stateList) { - sb.append(s).append(" "); + if (stateList != null) { + sb.append(" LL : "); + for (String s : stateList) { + sb.append(s).append(" "); + } } sb.append("\r\n"); sb.append("Reader:: ").append(reader.toString()); @@ -213,15 +231,20 @@ public class SSLFlowDelegate { * Upstream subscription strategy is to try and keep no more than * TARGET_BUFSIZE bytes in readBuf */ - class Reader extends SubscriberWrapper { - final SequentialScheduler scheduler; + final class Reader extends SubscriberWrapper implements FlowTube.TubeSubscriber { + // Maximum record size is 16k. + // Because SocketTube can feeds us up to 3 16K buffers, + // then setting this size to 16K means that the readBuf + // can store up to 64K-1 (16K-1 + 3*16K) static final int TARGET_BUFSIZE = 16 * 1024; + + final SequentialScheduler scheduler; volatile ByteBuffer readBuf; volatile boolean completing; final Object readBufferLock = new Object(); final Logger debugr = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); - class ReaderDownstreamPusher implements Runnable { + private final class ReaderDownstreamPusher implements Runnable { @Override public void run() { processData(); } } @@ -233,6 +256,11 @@ public class SSLFlowDelegate { readBuf.limit(0); // keep in read mode } + @Override + public boolean supportsRecycling() { + return recycler != null; + } + protected SchedulingAction enterScheduling() { return enterReadScheduling(); } @@ -250,7 +278,7 @@ public class SSLFlowDelegate { debugr.log("Adding %d bytes to read buffer", Utils.remaining(buffers)); addToReadBuf(buffers, complete); - scheduler.runOrSchedule(); + scheduler.runOrSchedule(exec); } @Override @@ -270,6 +298,9 @@ public class SSLFlowDelegate { @Override protected long upstreamWindowUpdate(long currentWindow, long downstreamQsize) { if (readBuf.remaining() > TARGET_BUFSIZE) { + if (debugr.on()) + debugr.log("readBuf has more than TARGET_BUFSIZE: %d", + readBuf.remaining()); return 0; } else { return super.upstreamWindowUpdate(currentWindow, downstreamQsize); @@ -285,6 +316,11 @@ public class SSLFlowDelegate { reallocReadBuf(); readBuf.put(buf); readBuf.flip(); + // should be safe to call inside lock + // since the only implementation + // offers the buffer to an unbounded queue. + // WARNING: do not touch buf after this point! + if (recycler != null) recycler.accept(buf); } if (complete) { this.completing = complete; @@ -293,7 +329,7 @@ public class SSLFlowDelegate { } void schedule() { - scheduler.runOrSchedule(); + scheduler.runOrSchedule(exec); } void stop() { @@ -303,8 +339,13 @@ public class SSLFlowDelegate { AtomicInteger count = new AtomicInteger(0); + // minimum number of bytes required to call unwrap. + // Usually this is 0, unless there was a buffer underflow. + // In this case we need to wait for more bytes than what + // we had before calling unwrap() again. + volatile int minBytesRequired; // work function where it all happens - void processData() { + final void processData() { try { if (debugr.on()) debugr.log("processData:" @@ -313,15 +354,23 @@ public class SSLFlowDelegate { + ", engine handshake status:" + engine.getHandshakeStatus()); int len; boolean complete = false; - while ((len = readBuf.remaining()) > 0) { + while (readBuf.remaining() > (len = minBytesRequired)) { boolean handshaking = false; try { EngineResult result; synchronized (readBufferLock) { complete = this.completing; + if (debugr.on()) debugr.log("Unwrapping: %s", readBuf.remaining()); + // Unless there is a BUFFER_UNDERFLOW, we should try to + // unwrap any number of bytes. Set minBytesRequired to 0: + // we only need to do that if minBytesRequired is not already 0. + len = len > 0 ? minBytesRequired = 0 : len; result = unwrapBuffer(readBuf); - if (debugr.on()) - debugr.log("Unwrapped: %s", result.result); + len = readBuf.remaining(); + if (debugr.on()) { + debugr.log("Unwrapped: result: %s", result.result); + debugr.log("Unwrapped: consumed: %s", result.bytesConsumed()); + } } if (result.bytesProduced() > 0) { if (debugr.on()) @@ -332,12 +381,19 @@ public class SSLFlowDelegate { if (result.status() == Status.BUFFER_UNDERFLOW) { if (debugr.on()) debugr.log("BUFFER_UNDERFLOW"); // not enough data in the read buffer... - requestMore(); + // no need to try to unwrap again unless we get more bytes + // than minBytesRequired = len in the read buffer. + minBytesRequired = len; synchronized (readBufferLock) { - // check if we have received some data + // more bytes could already have been added... + assert readBuf.remaining() >= len; + // check if we have received some data, and if so + // we can just re-spin the loop if (readBuf.remaining() > len) continue; - return; } + // request more data and return. + requestMore(); + return; } if (complete && result.status() == Status.CLOSED) { if (debugr.on()) debugr.log("Closed: completing"); @@ -352,8 +408,10 @@ public class SSLFlowDelegate { handshaking = true; } else { if ((handshakeState.getAndSet(NOT_HANDSHAKING)& ~DOING_TASKS) == HANDSHAKING) { - setALPN(); handshaking = false; + applicationBufferSize = engine.getSession().getApplicationBufferSize(); + packetBufferSize = engine.getSession().getPacketBufferSize(); + setALPN(); resumeActivity(); } } @@ -391,7 +449,8 @@ public class SSLFlowDelegate { case BUFFER_OVERFLOW: // may happen only if app size buffer was changed. // get it again if app buffer size changed - int appSize = engine.getSession().getApplicationBufferSize(); + int appSize = applicationBufferSize = + engine.getSession().getApplicationBufferSize(); ByteBuffer b = ByteBuffer.allocate(appSize + dst.position()); dst.flip(); b.put(dst); @@ -489,7 +548,7 @@ public class SSLFlowDelegate { @Override protected void incoming(List buffers, boolean complete) { - assert complete ? buffers == Utils.EMPTY_BB_LIST : true; + assert complete ? buffers == Utils.EMPTY_BB_LIST : true; assert buffers != Utils.EMPTY_BB_LIST ? complete == false : true; if (complete) { if (debugw.on()) debugw.log("adding SENTINEL"); @@ -549,6 +608,15 @@ public class SSLFlowDelegate { } } + void triggerWrite() { + synchronized (writeList) { + if (writeList.isEmpty()) { + writeList.add(HS_TRIGGER); + } + } + scheduler.runOrSchedule(); + } + private void processData() { boolean completing = isCompleting(); @@ -586,6 +654,8 @@ public class SSLFlowDelegate { handshaking = true; } else { if ((handshakeState.getAndSet(NOT_HANDSHAKING) & ~DOING_TASKS) == HANDSHAKING) { + applicationBufferSize = engine.getSession().getApplicationBufferSize(); + packetBufferSize = engine.getSession().getPacketBufferSize(); setALPN(); resumeActivity(); } @@ -630,8 +700,9 @@ public class SSLFlowDelegate { // Shouldn't happen. We allocated buffer with packet size // get it again if net buffer size was changed if (debugw.on()) debugw.log("BUFFER_OVERFLOW"); - int appSize = engine.getSession().getApplicationBufferSize(); - ByteBuffer b = ByteBuffer.allocate(appSize + dst.position()); + int netSize = packetBufferSize + = engine.getSession().getPacketBufferSize(); + ByteBuffer b = ByteBuffer.allocate(netSize + dst.position()); dst.flip(); b.put(dst); dst = b; @@ -759,13 +830,16 @@ public class SSLFlowDelegate { } final AtomicInteger handshakeState; - final ConcurrentLinkedQueue stateList = new ConcurrentLinkedQueue<>(); + final ConcurrentLinkedQueue stateList = + debug.on() ? new ConcurrentLinkedQueue<>() : null; private boolean doHandshake(EngineResult r, int caller) { // unconditionally sets the HANDSHAKING bit, while preserving DOING_TASKS handshakeState.getAndAccumulate(HANDSHAKING, (current, update) -> update | (current & DOING_TASKS)); - stateList.add(r.handshakeStatus().toString()); - stateList.add(Integer.toString(caller)); + if (stateList != null && debug.on()) { + stateList.add(r.handshakeStatus().toString()); + stateList.add(Integer.toString(caller)); + } switch (r.handshakeStatus()) { case NEED_TASK: int s = handshakeState.getAndUpdate((current) -> current | DOING_TASKS); @@ -778,7 +852,7 @@ public class SSLFlowDelegate { return false; // executeTasks will resume activity case NEED_WRAP: if (caller == READER) { - writer.addData(HS_TRIGGER); + writer.triggerWrite(); return false; } break; @@ -818,7 +892,6 @@ public class SSLFlowDelegate { } } while (true); handshakeState.getAndUpdate((current) -> current & ~DOING_TASKS); - //writer.addData(HS_TRIGGER); resumeActivity(); } catch (Throwable t) { handleError(t); @@ -839,7 +912,17 @@ public class SSLFlowDelegate { if (engine.isInboundDone() && !engine.isOutboundDone()) { if (debug.on()) debug.log("doClosure: close_notify received"); close_notify_received = true; - doHandshake(r, READER); + if (!writer.scheduler.isStopped()) { + doHandshake(r, READER); + } else { + // We have received closed notify, but we + // won't be able to send the acknowledgement. + // Nothing more will come from the socket either, + // so mark the reader as completed. + synchronized (reader.readBufferLock) { + reader.completing = true; + } + } } } return r; @@ -914,12 +997,22 @@ public class SSLFlowDelegate { } } - public ByteBuffer getNetBuffer() { - return ByteBuffer.allocate(engine.getSession().getPacketBufferSize()); + volatile int packetBufferSize; + final ByteBuffer getNetBuffer() { + int netSize = packetBufferSize; + if (netSize <= 0) { + packetBufferSize = netSize = engine.getSession().getPacketBufferSize(); + } + return ByteBuffer.allocate(netSize); } - private ByteBuffer getAppBuffer() { - return ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); + volatile int applicationBufferSize; + final ByteBuffer getAppBuffer() { + int appSize = applicationBufferSize; + if (appSize <= 0) { + applicationBufferSize = appSize = engine.getSession().getApplicationBufferSize(); + } + return ByteBuffer.allocate(appSize); } final String dbgString() { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java index 5160e9985d3..8647a133f3c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java @@ -77,6 +77,13 @@ public class SSLTube implements FlowTube { private volatile boolean finished; public SSLTube(SSLEngine engine, Executor executor, FlowTube tube) { + this(engine, executor, null, tube); + } + + public SSLTube(SSLEngine engine, + Executor executor, + Consumer recycler, + FlowTube tube) { Objects.requireNonNull(engine); Objects.requireNonNull(executor); this.tube = Objects.requireNonNull(tube); @@ -85,15 +92,17 @@ public class SSLTube implements FlowTube { this.engine = engine; sslDelegate = new SSLTubeFlowDelegate(engine, executor, + recycler, readSubscriber, tube); } final class SSLTubeFlowDelegate extends SSLFlowDelegate { SSLTubeFlowDelegate(SSLEngine engine, Executor executor, + Consumer recycler, SSLSubscriberWrapper readSubscriber, FlowTube tube) { - super(engine, executor, readSubscriber, tube); + super(engine, executor, recycler, readSubscriber, tube); } protected SchedulingAction enterReadScheduling() { readSubscriber.processPendingSubscriber(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java index 64771592d89..5fffd74b54d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java @@ -306,14 +306,16 @@ public abstract class SubscriberWrapper downstreamSubscription); } + boolean datasent = false; while (!outputQ.isEmpty() && downstreamSubscription.tryDecrement()) { List b = outputQ.poll(); if (debug.on()) debug.log("DownstreamPusher: Pushing %d bytes downstream", Utils.remaining(b)); downstreamSubscriber.onNext(b); + datasent = true; } - upstreamWindowUpdate(); + if (datasent) upstreamWindowUpdate(); checkCompletion(); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java index a10115026b8..7b2ebdce597 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java @@ -44,10 +44,14 @@ import java.net.URI; import java.net.URLPermission; import java.net.http.HttpHeaders; import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; +import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.security.AccessController; import java.security.PrivilegedAction; +import java.text.Normalizer; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -581,25 +585,6 @@ public final class Utils { return (int) remain; } - public static long remaining(ByteBufferReference[] refs) { - long remain = 0; - for (ByteBufferReference ref : refs) { - remain += ref.get().remaining(); - } - return remain; - } - - public static int remaining(ByteBufferReference[] refs, int max) { - long remain = 0; - for (ByteBufferReference ref : refs) { - remain += ref.get().remaining(); - if (remain > max) { - throw new IllegalArgumentException("too many bytes"); - } - } - return (int) remain; - } - public static int remaining(ByteBuffer[] refs, int max) { long remain = 0; for (ByteBuffer b : refs) { @@ -623,7 +608,6 @@ public final class Utils { public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0); public static final ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0]; public static final List EMPTY_BB_LIST = List.of(); - public static final ByteBufferReference[] EMPTY_BBR_ARRAY = new ByteBufferReference[0]; /** * Returns a slice of size {@code amount} from the given buffer. If the @@ -959,4 +943,55 @@ public final class Utils { return 1 << (32 - Integer.numberOfLeadingZeros(n - 1)); } } + + // -- toAsciiString-like support to encode path and query URI segments + + private static final char[] hexDigits = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + private static void appendEscape(StringBuilder sb, byte b) { + sb.append('%'); + sb.append(hexDigits[(b >> 4) & 0x0f]); + sb.append(hexDigits[(b >> 0) & 0x0f]); + } + + // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets, + // assuming that s is otherwise legal + // + public static String encode(String s) { + int n = s.length(); + if (n == 0) + return s; + + // First check whether we actually need to encode + for (int i = 0;;) { + if (s.charAt(i) >= '\u0080') + break; + if (++i >= n) + return s; + } + + String ns = Normalizer.normalize(s, Normalizer.Form.NFC); + ByteBuffer bb = null; + try { + bb = StandardCharsets.UTF_8.newEncoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT) + .encode(CharBuffer.wrap(ns)); + } catch (CharacterCodingException x) { + assert false : x; + } + + StringBuilder sb = new StringBuilder(); + while (bb.hasRemaining()) { + int b = bb.get() & 0xff; + if (b >= 0x80) + appendEscape(sb, (byte)b); + else + sb.append((char)b); + } + return sb.toString(); + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Huffman.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Huffman.java index 2b7e1b626e9..3d1f022d2d0 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Huffman.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Huffman.java @@ -27,655 +27,60 @@ package jdk.internal.net.http.hpack; import java.io.IOException; import java.nio.ByteBuffer; -import static java.lang.String.format; - /** - * Huffman coding table. - * - *

      Instances of this class are safe for use by multiple threads. + * Huffman coding. * * @since 9 */ public final class Huffman { - // TODO: check if reset is done in both reader and writer + public interface Reader { - static final class Reader { - - private Node curr; // position in the trie - private int len; // length of the path from the root to 'curr' - private int p; // byte probe - - { - reset(); - } - - public void read(ByteBuffer source, - Appendable destination, - boolean isLast) throws IOException { - read(source, destination, true, isLast); - } - - // Takes 'isLast' rather than returns whether the reading is done or - // not, for more informative exceptions. void read(ByteBuffer source, Appendable destination, - boolean reportEOS, /* reportEOS is exposed for tests */ - boolean isLast) throws IOException { - Node c = curr; - int l = len; - /* - Since ByteBuffer is itself stateful, its position is - remembered here NOT as a part of Reader's state, - but to set it back in the case of a failure - */ - int pos = source.position(); + boolean isLast) throws IOException; - while (source.hasRemaining()) { - int d = source.get(); - for (; p != 0; p >>= 1) { - c = c.getChild(p & d); - l++; - if (c.isLeaf()) { - if (reportEOS && c.isEOSPath) { - throw new IOException("Encountered EOS"); - } - char ch; - try { - ch = c.getChar(); - } catch (IllegalStateException e) { - source.position(pos); // do we need this? - throw new IOException(e); - } - try { - destination.append(ch); - } catch (IOException e) { - source.position(pos); // do we need this? - throw e; - } - c = INSTANCE.root; - l = 0; - } - curr = c; - len = l; - } - resetProbe(); - pos++; - } - if (!isLast) { - return; // it's too early to jump to any conclusions, let's wait - } - if (c.isLeaf()) { - return; // it's perfectly ok, no extra padding bits - } - if (c.isEOSPath && len <= 7) { - return; // it's ok, some extra padding bits - } - if (c.isEOSPath) { - throw new IOException( - "Padding is too long (len=" + len + ") " + - "or unexpected end of data"); - } - throw new IOException( - "Not a EOS prefix padding or unexpected end of data"); - } - - public void reset() { - curr = INSTANCE.root; - len = 0; - resetProbe(); - } - - private void resetProbe() { - p = 0x80; - } + /** + * Brings this reader to the state it had upon construction. + */ + void reset(); } - static final class Writer { + public interface Writer { - private int pos; // position in 'source' - private int avail = 8; // number of least significant bits available in 'curr' - private int curr; // next byte to put to the destination - private int rem; // number of least significant bits in 'code' yet to be processed - private int code; // current code being written + Writer from(CharSequence input, int start, int end); - private CharSequence source; - private int end; + boolean write(ByteBuffer destination); - public Writer from(CharSequence input, int start, int end) { - if (start < 0 || end < 0 || end > input.length() || start > end) { - throw new IndexOutOfBoundsException( - String.format("input.length()=%s, start=%s, end=%s", - input.length(), start, end)); - } - pos = start; - this.end = end; - this.source = input; - return this; - } + /** + * Brings this writer to the state it had upon construction. + * + * @return this writer + */ + Writer reset(); - public boolean write(ByteBuffer destination) { - for (; pos < end; pos++) { - if (rem == 0) { - Code desc = INSTANCE.codeOf(source.charAt(pos)); - rem = desc.length; - code = desc.code; - } - while (rem > 0) { - if (rem < avail) { - curr |= (code << (avail - rem)); - avail -= rem; - rem = 0; - } else { - int c = (curr | (code >>> (rem - avail))); - if (destination.hasRemaining()) { - destination.put((byte) c); - } else { - return false; - } - curr = c; - code <<= (32 - rem + avail); // throw written bits off the cliff (is this Sparta?) - code >>>= (32 - rem + avail); // return to the position - rem -= avail; - curr = 0; - avail = 8; - } - } - } + /** + * Calculates the number of bytes required to represent a subsequence of + * the given {@code CharSequence} using the Huffman coding. + * + * @param value + * characters + * @param start + * the start index, inclusive + * @param end + * the end index, exclusive + * + * @return number of bytes + * @throws NullPointerException + * if the value is null + * @throws IndexOutOfBoundsException + * if any invocation of {@code value.charAt(i)}, where + * {@code start <= i < end}, throws an IndexOutOfBoundsException + */ + int lengthOf(CharSequence value, int start, int end); - if (avail < 8) { // have to pad - if (destination.hasRemaining()) { - destination.put((byte) (curr | (INSTANCE.EOS.code >>> (INSTANCE.EOS.length - avail)))); - avail = 8; - } else { - return false; - } - } - - return true; - } - - public Writer reset() { - source = null; - end = -1; - pos = -1; - avail = 8; - curr = 0; - code = 0; - return this; - } - } - - /** - * Shared instance. - */ - public static final Huffman INSTANCE = new Huffman(); - - private final Code EOS = new Code(0x3fffffff, 30); - private final Code[] codes = new Code[257]; - private final Node root = new Node() { - @Override - public String toString() { return "root"; } - }; - - // TODO: consider builder and immutable trie - private Huffman() { - // @formatter:off - addChar(0, 0x1ff8, 13); - addChar(1, 0x7fffd8, 23); - addChar(2, 0xfffffe2, 28); - addChar(3, 0xfffffe3, 28); - addChar(4, 0xfffffe4, 28); - addChar(5, 0xfffffe5, 28); - addChar(6, 0xfffffe6, 28); - addChar(7, 0xfffffe7, 28); - addChar(8, 0xfffffe8, 28); - addChar(9, 0xffffea, 24); - addChar(10, 0x3ffffffc, 30); - addChar(11, 0xfffffe9, 28); - addChar(12, 0xfffffea, 28); - addChar(13, 0x3ffffffd, 30); - addChar(14, 0xfffffeb, 28); - addChar(15, 0xfffffec, 28); - addChar(16, 0xfffffed, 28); - addChar(17, 0xfffffee, 28); - addChar(18, 0xfffffef, 28); - addChar(19, 0xffffff0, 28); - addChar(20, 0xffffff1, 28); - addChar(21, 0xffffff2, 28); - addChar(22, 0x3ffffffe, 30); - addChar(23, 0xffffff3, 28); - addChar(24, 0xffffff4, 28); - addChar(25, 0xffffff5, 28); - addChar(26, 0xffffff6, 28); - addChar(27, 0xffffff7, 28); - addChar(28, 0xffffff8, 28); - addChar(29, 0xffffff9, 28); - addChar(30, 0xffffffa, 28); - addChar(31, 0xffffffb, 28); - addChar(32, 0x14, 6); - addChar(33, 0x3f8, 10); - addChar(34, 0x3f9, 10); - addChar(35, 0xffa, 12); - addChar(36, 0x1ff9, 13); - addChar(37, 0x15, 6); - addChar(38, 0xf8, 8); - addChar(39, 0x7fa, 11); - addChar(40, 0x3fa, 10); - addChar(41, 0x3fb, 10); - addChar(42, 0xf9, 8); - addChar(43, 0x7fb, 11); - addChar(44, 0xfa, 8); - addChar(45, 0x16, 6); - addChar(46, 0x17, 6); - addChar(47, 0x18, 6); - addChar(48, 0x0, 5); - addChar(49, 0x1, 5); - addChar(50, 0x2, 5); - addChar(51, 0x19, 6); - addChar(52, 0x1a, 6); - addChar(53, 0x1b, 6); - addChar(54, 0x1c, 6); - addChar(55, 0x1d, 6); - addChar(56, 0x1e, 6); - addChar(57, 0x1f, 6); - addChar(58, 0x5c, 7); - addChar(59, 0xfb, 8); - addChar(60, 0x7ffc, 15); - addChar(61, 0x20, 6); - addChar(62, 0xffb, 12); - addChar(63, 0x3fc, 10); - addChar(64, 0x1ffa, 13); - addChar(65, 0x21, 6); - addChar(66, 0x5d, 7); - addChar(67, 0x5e, 7); - addChar(68, 0x5f, 7); - addChar(69, 0x60, 7); - addChar(70, 0x61, 7); - addChar(71, 0x62, 7); - addChar(72, 0x63, 7); - addChar(73, 0x64, 7); - addChar(74, 0x65, 7); - addChar(75, 0x66, 7); - addChar(76, 0x67, 7); - addChar(77, 0x68, 7); - addChar(78, 0x69, 7); - addChar(79, 0x6a, 7); - addChar(80, 0x6b, 7); - addChar(81, 0x6c, 7); - addChar(82, 0x6d, 7); - addChar(83, 0x6e, 7); - addChar(84, 0x6f, 7); - addChar(85, 0x70, 7); - addChar(86, 0x71, 7); - addChar(87, 0x72, 7); - addChar(88, 0xfc, 8); - addChar(89, 0x73, 7); - addChar(90, 0xfd, 8); - addChar(91, 0x1ffb, 13); - addChar(92, 0x7fff0, 19); - addChar(93, 0x1ffc, 13); - addChar(94, 0x3ffc, 14); - addChar(95, 0x22, 6); - addChar(96, 0x7ffd, 15); - addChar(97, 0x3, 5); - addChar(98, 0x23, 6); - addChar(99, 0x4, 5); - addChar(100, 0x24, 6); - addChar(101, 0x5, 5); - addChar(102, 0x25, 6); - addChar(103, 0x26, 6); - addChar(104, 0x27, 6); - addChar(105, 0x6, 5); - addChar(106, 0x74, 7); - addChar(107, 0x75, 7); - addChar(108, 0x28, 6); - addChar(109, 0x29, 6); - addChar(110, 0x2a, 6); - addChar(111, 0x7, 5); - addChar(112, 0x2b, 6); - addChar(113, 0x76, 7); - addChar(114, 0x2c, 6); - addChar(115, 0x8, 5); - addChar(116, 0x9, 5); - addChar(117, 0x2d, 6); - addChar(118, 0x77, 7); - addChar(119, 0x78, 7); - addChar(120, 0x79, 7); - addChar(121, 0x7a, 7); - addChar(122, 0x7b, 7); - addChar(123, 0x7ffe, 15); - addChar(124, 0x7fc, 11); - addChar(125, 0x3ffd, 14); - addChar(126, 0x1ffd, 13); - addChar(127, 0xffffffc, 28); - addChar(128, 0xfffe6, 20); - addChar(129, 0x3fffd2, 22); - addChar(130, 0xfffe7, 20); - addChar(131, 0xfffe8, 20); - addChar(132, 0x3fffd3, 22); - addChar(133, 0x3fffd4, 22); - addChar(134, 0x3fffd5, 22); - addChar(135, 0x7fffd9, 23); - addChar(136, 0x3fffd6, 22); - addChar(137, 0x7fffda, 23); - addChar(138, 0x7fffdb, 23); - addChar(139, 0x7fffdc, 23); - addChar(140, 0x7fffdd, 23); - addChar(141, 0x7fffde, 23); - addChar(142, 0xffffeb, 24); - addChar(143, 0x7fffdf, 23); - addChar(144, 0xffffec, 24); - addChar(145, 0xffffed, 24); - addChar(146, 0x3fffd7, 22); - addChar(147, 0x7fffe0, 23); - addChar(148, 0xffffee, 24); - addChar(149, 0x7fffe1, 23); - addChar(150, 0x7fffe2, 23); - addChar(151, 0x7fffe3, 23); - addChar(152, 0x7fffe4, 23); - addChar(153, 0x1fffdc, 21); - addChar(154, 0x3fffd8, 22); - addChar(155, 0x7fffe5, 23); - addChar(156, 0x3fffd9, 22); - addChar(157, 0x7fffe6, 23); - addChar(158, 0x7fffe7, 23); - addChar(159, 0xffffef, 24); - addChar(160, 0x3fffda, 22); - addChar(161, 0x1fffdd, 21); - addChar(162, 0xfffe9, 20); - addChar(163, 0x3fffdb, 22); - addChar(164, 0x3fffdc, 22); - addChar(165, 0x7fffe8, 23); - addChar(166, 0x7fffe9, 23); - addChar(167, 0x1fffde, 21); - addChar(168, 0x7fffea, 23); - addChar(169, 0x3fffdd, 22); - addChar(170, 0x3fffde, 22); - addChar(171, 0xfffff0, 24); - addChar(172, 0x1fffdf, 21); - addChar(173, 0x3fffdf, 22); - addChar(174, 0x7fffeb, 23); - addChar(175, 0x7fffec, 23); - addChar(176, 0x1fffe0, 21); - addChar(177, 0x1fffe1, 21); - addChar(178, 0x3fffe0, 22); - addChar(179, 0x1fffe2, 21); - addChar(180, 0x7fffed, 23); - addChar(181, 0x3fffe1, 22); - addChar(182, 0x7fffee, 23); - addChar(183, 0x7fffef, 23); - addChar(184, 0xfffea, 20); - addChar(185, 0x3fffe2, 22); - addChar(186, 0x3fffe3, 22); - addChar(187, 0x3fffe4, 22); - addChar(188, 0x7ffff0, 23); - addChar(189, 0x3fffe5, 22); - addChar(190, 0x3fffe6, 22); - addChar(191, 0x7ffff1, 23); - addChar(192, 0x3ffffe0, 26); - addChar(193, 0x3ffffe1, 26); - addChar(194, 0xfffeb, 20); - addChar(195, 0x7fff1, 19); - addChar(196, 0x3fffe7, 22); - addChar(197, 0x7ffff2, 23); - addChar(198, 0x3fffe8, 22); - addChar(199, 0x1ffffec, 25); - addChar(200, 0x3ffffe2, 26); - addChar(201, 0x3ffffe3, 26); - addChar(202, 0x3ffffe4, 26); - addChar(203, 0x7ffffde, 27); - addChar(204, 0x7ffffdf, 27); - addChar(205, 0x3ffffe5, 26); - addChar(206, 0xfffff1, 24); - addChar(207, 0x1ffffed, 25); - addChar(208, 0x7fff2, 19); - addChar(209, 0x1fffe3, 21); - addChar(210, 0x3ffffe6, 26); - addChar(211, 0x7ffffe0, 27); - addChar(212, 0x7ffffe1, 27); - addChar(213, 0x3ffffe7, 26); - addChar(214, 0x7ffffe2, 27); - addChar(215, 0xfffff2, 24); - addChar(216, 0x1fffe4, 21); - addChar(217, 0x1fffe5, 21); - addChar(218, 0x3ffffe8, 26); - addChar(219, 0x3ffffe9, 26); - addChar(220, 0xffffffd, 28); - addChar(221, 0x7ffffe3, 27); - addChar(222, 0x7ffffe4, 27); - addChar(223, 0x7ffffe5, 27); - addChar(224, 0xfffec, 20); - addChar(225, 0xfffff3, 24); - addChar(226, 0xfffed, 20); - addChar(227, 0x1fffe6, 21); - addChar(228, 0x3fffe9, 22); - addChar(229, 0x1fffe7, 21); - addChar(230, 0x1fffe8, 21); - addChar(231, 0x7ffff3, 23); - addChar(232, 0x3fffea, 22); - addChar(233, 0x3fffeb, 22); - addChar(234, 0x1ffffee, 25); - addChar(235, 0x1ffffef, 25); - addChar(236, 0xfffff4, 24); - addChar(237, 0xfffff5, 24); - addChar(238, 0x3ffffea, 26); - addChar(239, 0x7ffff4, 23); - addChar(240, 0x3ffffeb, 26); - addChar(241, 0x7ffffe6, 27); - addChar(242, 0x3ffffec, 26); - addChar(243, 0x3ffffed, 26); - addChar(244, 0x7ffffe7, 27); - addChar(245, 0x7ffffe8, 27); - addChar(246, 0x7ffffe9, 27); - addChar(247, 0x7ffffea, 27); - addChar(248, 0x7ffffeb, 27); - addChar(249, 0xffffffe, 28); - addChar(250, 0x7ffffec, 27); - addChar(251, 0x7ffffed, 27); - addChar(252, 0x7ffffee, 27); - addChar(253, 0x7ffffef, 27); - addChar(254, 0x7fffff0, 27); - addChar(255, 0x3ffffee, 26); - addEOS (256, EOS.code, EOS.length); - // @formatter:on - } - - - /** - * Calculates the number of bytes required to represent the given {@code - * CharSequence} with the Huffman coding. - * - * @param value - * characters - * - * @return number of bytes - * - * @throws NullPointerException - * if the value is null - */ - public int lengthOf(CharSequence value) { - return lengthOf(value, 0, value.length()); - } - - /** - * Calculates the number of bytes required to represent a subsequence of the - * given {@code CharSequence} with the Huffman coding. - * - * @param value - * characters - * @param start - * the start index, inclusive - * @param end - * the end index, exclusive - * - * @return number of bytes - * - * @throws NullPointerException - * if the value is null - * @throws IndexOutOfBoundsException - * if any invocation of {@code value.charAt(i)}, where - * {@code start <= i < end} would throw an IndexOutOfBoundsException - */ - public int lengthOf(CharSequence value, int start, int end) { - int len = 0; - for (int i = start; i < end; i++) { - char c = value.charAt(i); - len += INSTANCE.codeOf(c).length; - } - // Integer division with ceiling, assumption: - assert (len / 8 + (len % 8 != 0 ? 1 : 0)) == (len + 7) / 8 : len; - return (len + 7) / 8; - } - - private void addChar(int c, int code, int bitLength) { - addLeaf(c, code, bitLength, false); - codes[c] = new Code(code, bitLength); - } - - private void addEOS(int c, int code, int bitLength) { - addLeaf(c, code, bitLength, true); - codes[c] = new Code(code, bitLength); - } - - private void addLeaf(int c, int code, int bitLength, boolean isEOS) { - if (bitLength < 1) { - throw new IllegalArgumentException("bitLength < 1"); - } - Node curr = root; - for (int p = 1 << bitLength - 1; p != 0 && !curr.isLeaf(); p = p >> 1) { - curr.isEOSPath |= isEOS; // If it's already true, it can't become false - curr = curr.addChildIfAbsent(p & code); - } - curr.isEOSPath |= isEOS; // The last one needs to have this property as well - if (curr.isLeaf()) { - throw new IllegalStateException("Specified code is already taken"); - } - curr.setChar((char) c); - } - - private Code codeOf(char c) { - if (c > 255) { - throw new IllegalArgumentException("char=" + ((int) c)); - } - return codes[c]; - } - - // - // For debugging/testing purposes - // - Node getRoot() { - return root; - } - - // - // Guarantees: - // - // if (isLeaf() == true) => getChar() is a legal call - // if (isLeaf() == false) => getChild(i) is a legal call (though it can - // return null) - // - static class Node { - - Node left; - Node right; - boolean isEOSPath; - - boolean charIsSet; - char c; - - Node getChild(int selector) { - if (isLeaf()) { - throw new IllegalStateException("This is a leaf node"); - } - Node result = selector == 0 ? left : right; - if (result == null) { - throw new IllegalStateException(format( - "Node doesn't have a child (selector=%s)", selector)); - } - return result; - } - - boolean isLeaf() { - return charIsSet; - } - - char getChar() { - if (!isLeaf()) { - throw new IllegalStateException("This node is not a leaf node"); - } - return c; - } - - void setChar(char c) { - if (charIsSet) { - throw new IllegalStateException( - "This node has been taken already"); - } - if (left != null || right != null) { - throw new IllegalStateException("The node cannot be made " - + "a leaf as it's already has a child"); - } - this.c = c; - charIsSet = true; - } - - Node addChildIfAbsent(int i) { - if (charIsSet) { - throw new IllegalStateException("The node cannot have a child " - + "as it's already a leaf node"); - } - Node child; - if (i == 0) { - if ((child = left) == null) { - child = left = new Node(); - } - } else { - if ((child = right) == null) { - child = right = new Node(); - } - } - return child; - } - - @Override - public String toString() { - if (isLeaf()) { - if (isEOSPath) { - return "EOS"; - } else { - return format("char: (%3s) '%s'", (int) c, c); - } - } - return "/\\"; - } - } - - // TODO: value-based class? - // FIXME: can we re-use Node instead of this class? - private static final class Code { - - final int code; - final int length; - - private Code(int code, int length) { - this.code = code; - this.length = length; - } - - public int getCode() { - return code; - } - - public int getLength() { - return length; - } - - @Override - public String toString() { - long p = 1 << length; - return Long.toBinaryString(code + p).substring(1) - + ", length=" + length; + default int lengthOf(CharSequence value) { + return lengthOf(value, 0, value.length()); } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/NaiveHuffman.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/NaiveHuffman.java new file mode 100644 index 00000000000..8a076ca67cb --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/NaiveHuffman.java @@ -0,0 +1,691 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.net.http.hpack; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import static java.lang.String.format; + +/** + * Huffman coding table. + * + *

      Instances of this class are safe for use by multiple threads. + * + * @since 9 + */ +public final class NaiveHuffman { + + // TODO: check if reset is done in both reader and writer + + static final class Reader implements Huffman.Reader { + + private Node curr; // position in the trie + private int len; // length of the path from the root to 'curr' + private int p; // byte probe + + { + reset(); + } + + @Override + public void read(ByteBuffer source, + Appendable destination, + boolean isLast) throws IOException { + read(source, destination, true, isLast); + } + + // Takes 'isLast' rather than returns whether the reading is done or + // not, for more informative exceptions. + void read(ByteBuffer source, + Appendable destination, + boolean reportEOS, /* reportEOS is exposed for tests */ + boolean isLast) throws IOException { + Node c = curr; + int l = len; + /* + Since ByteBuffer is itself stateful, its position is + remembered here NOT as a part of Reader's state, + but to set it back in the case of a failure + */ + int pos = source.position(); + + while (source.hasRemaining()) { + int d = source.get(); + for (; p != 0; p >>= 1) { + c = c.getChild(p & d); + l++; + if (c.isLeaf()) { + if (reportEOS && c.isEOSPath) { + throw new IOException("Encountered EOS"); + } + char ch; + try { + ch = c.getChar(); + } catch (IllegalStateException e) { + source.position(pos); // do we need this? + throw new IOException(e); + } + try { + destination.append(ch); + } catch (IOException e) { + source.position(pos); // do we need this? + throw e; + } + c = INSTANCE.root; + l = 0; + } + curr = c; + len = l; + } + resetProbe(); + pos++; + } + if (!isLast) { + return; // it's too early to jump to any conclusions, let's wait + } + if (c.isLeaf()) { + return; // it's perfectly ok, no extra padding bits + } + if (c.isEOSPath && len <= 7) { + return; // it's ok, some extra padding bits + } + if (c.isEOSPath) { + throw new IOException( + "Padding is too long (len=" + len + ") " + + "or unexpected end of data"); + } + throw new IOException( + "Not a EOS prefix padding or unexpected end of data"); + } + + @Override + public void reset() { + curr = INSTANCE.root; + len = 0; + resetProbe(); + } + + private void resetProbe() { + p = 0x80; + } + } + + static final class Writer implements Huffman.Writer { + + private int pos; // position in 'source' + private int avail = 8; // number of least significant bits available in 'curr' + private int curr; // next byte to put to the destination + private int rem; // number of least significant bits in 'code' yet to be processed + private int code; // current code being written + + private CharSequence source; + private int end; + + @Override + public Writer from(CharSequence input, int start, int end) { + if (start < 0 || end < 0 || end > input.length() || start > end) { + throw new IndexOutOfBoundsException( + String.format("input.length()=%s, start=%s, end=%s", + input.length(), start, end)); + } + pos = start; + this.end = end; + this.source = input; + return this; + } + + @Override + public boolean write(ByteBuffer destination) { + for (; pos < end; pos++) { + if (rem == 0) { + Code desc = INSTANCE.codeOf(source.charAt(pos)); + rem = desc.length; + code = desc.code; + } + while (rem > 0) { + if (rem < avail) { + curr |= (code << (avail - rem)); + avail -= rem; + rem = 0; + } else { + int c = (curr | (code >>> (rem - avail))); + if (destination.hasRemaining()) { + destination.put((byte) c); + } else { + return false; + } + curr = c; + code <<= (32 - rem + avail); // throw written bits off the cliff (is this Sparta?) + code >>>= (32 - rem + avail); // return to the position + rem -= avail; + curr = 0; + avail = 8; + } + } + } + + if (avail < 8) { // have to pad + if (destination.hasRemaining()) { + destination.put((byte) (curr | (INSTANCE.EOS.code >>> (INSTANCE.EOS.length - avail)))); + avail = 8; + } else { + return false; + } + } + + return true; + } + + @Override + public Writer reset() { + source = null; + end = -1; + pos = -1; + avail = 8; + curr = 0; + code = 0; + return this; + } + + @Override + public int lengthOf(CharSequence value, int start, int end) { + return INSTANCE.lengthOf(value, start, end); + } + } + + /** + * Shared instance. + */ + public static final NaiveHuffman INSTANCE = new NaiveHuffman(); + + private final Code EOS = new Code(0x3fffffff, 30); + private final Code[] codes = new Code[257]; + private final Node root = new Node() { + @Override + public String toString() { return "root"; } + }; + + // TODO: consider builder and immutable trie + private NaiveHuffman() { + // @formatter:off + addChar(0, 0x1ff8, 13); + addChar(1, 0x7fffd8, 23); + addChar(2, 0xfffffe2, 28); + addChar(3, 0xfffffe3, 28); + addChar(4, 0xfffffe4, 28); + addChar(5, 0xfffffe5, 28); + addChar(6, 0xfffffe6, 28); + addChar(7, 0xfffffe7, 28); + addChar(8, 0xfffffe8, 28); + addChar(9, 0xffffea, 24); + addChar(10, 0x3ffffffc, 30); + addChar(11, 0xfffffe9, 28); + addChar(12, 0xfffffea, 28); + addChar(13, 0x3ffffffd, 30); + addChar(14, 0xfffffeb, 28); + addChar(15, 0xfffffec, 28); + addChar(16, 0xfffffed, 28); + addChar(17, 0xfffffee, 28); + addChar(18, 0xfffffef, 28); + addChar(19, 0xffffff0, 28); + addChar(20, 0xffffff1, 28); + addChar(21, 0xffffff2, 28); + addChar(22, 0x3ffffffe, 30); + addChar(23, 0xffffff3, 28); + addChar(24, 0xffffff4, 28); + addChar(25, 0xffffff5, 28); + addChar(26, 0xffffff6, 28); + addChar(27, 0xffffff7, 28); + addChar(28, 0xffffff8, 28); + addChar(29, 0xffffff9, 28); + addChar(30, 0xffffffa, 28); + addChar(31, 0xffffffb, 28); + addChar(32, 0x14, 6); + addChar(33, 0x3f8, 10); + addChar(34, 0x3f9, 10); + addChar(35, 0xffa, 12); + addChar(36, 0x1ff9, 13); + addChar(37, 0x15, 6); + addChar(38, 0xf8, 8); + addChar(39, 0x7fa, 11); + addChar(40, 0x3fa, 10); + addChar(41, 0x3fb, 10); + addChar(42, 0xf9, 8); + addChar(43, 0x7fb, 11); + addChar(44, 0xfa, 8); + addChar(45, 0x16, 6); + addChar(46, 0x17, 6); + addChar(47, 0x18, 6); + addChar(48, 0x0, 5); + addChar(49, 0x1, 5); + addChar(50, 0x2, 5); + addChar(51, 0x19, 6); + addChar(52, 0x1a, 6); + addChar(53, 0x1b, 6); + addChar(54, 0x1c, 6); + addChar(55, 0x1d, 6); + addChar(56, 0x1e, 6); + addChar(57, 0x1f, 6); + addChar(58, 0x5c, 7); + addChar(59, 0xfb, 8); + addChar(60, 0x7ffc, 15); + addChar(61, 0x20, 6); + addChar(62, 0xffb, 12); + addChar(63, 0x3fc, 10); + addChar(64, 0x1ffa, 13); + addChar(65, 0x21, 6); + addChar(66, 0x5d, 7); + addChar(67, 0x5e, 7); + addChar(68, 0x5f, 7); + addChar(69, 0x60, 7); + addChar(70, 0x61, 7); + addChar(71, 0x62, 7); + addChar(72, 0x63, 7); + addChar(73, 0x64, 7); + addChar(74, 0x65, 7); + addChar(75, 0x66, 7); + addChar(76, 0x67, 7); + addChar(77, 0x68, 7); + addChar(78, 0x69, 7); + addChar(79, 0x6a, 7); + addChar(80, 0x6b, 7); + addChar(81, 0x6c, 7); + addChar(82, 0x6d, 7); + addChar(83, 0x6e, 7); + addChar(84, 0x6f, 7); + addChar(85, 0x70, 7); + addChar(86, 0x71, 7); + addChar(87, 0x72, 7); + addChar(88, 0xfc, 8); + addChar(89, 0x73, 7); + addChar(90, 0xfd, 8); + addChar(91, 0x1ffb, 13); + addChar(92, 0x7fff0, 19); + addChar(93, 0x1ffc, 13); + addChar(94, 0x3ffc, 14); + addChar(95, 0x22, 6); + addChar(96, 0x7ffd, 15); + addChar(97, 0x3, 5); + addChar(98, 0x23, 6); + addChar(99, 0x4, 5); + addChar(100, 0x24, 6); + addChar(101, 0x5, 5); + addChar(102, 0x25, 6); + addChar(103, 0x26, 6); + addChar(104, 0x27, 6); + addChar(105, 0x6, 5); + addChar(106, 0x74, 7); + addChar(107, 0x75, 7); + addChar(108, 0x28, 6); + addChar(109, 0x29, 6); + addChar(110, 0x2a, 6); + addChar(111, 0x7, 5); + addChar(112, 0x2b, 6); + addChar(113, 0x76, 7); + addChar(114, 0x2c, 6); + addChar(115, 0x8, 5); + addChar(116, 0x9, 5); + addChar(117, 0x2d, 6); + addChar(118, 0x77, 7); + addChar(119, 0x78, 7); + addChar(120, 0x79, 7); + addChar(121, 0x7a, 7); + addChar(122, 0x7b, 7); + addChar(123, 0x7ffe, 15); + addChar(124, 0x7fc, 11); + addChar(125, 0x3ffd, 14); + addChar(126, 0x1ffd, 13); + addChar(127, 0xffffffc, 28); + addChar(128, 0xfffe6, 20); + addChar(129, 0x3fffd2, 22); + addChar(130, 0xfffe7, 20); + addChar(131, 0xfffe8, 20); + addChar(132, 0x3fffd3, 22); + addChar(133, 0x3fffd4, 22); + addChar(134, 0x3fffd5, 22); + addChar(135, 0x7fffd9, 23); + addChar(136, 0x3fffd6, 22); + addChar(137, 0x7fffda, 23); + addChar(138, 0x7fffdb, 23); + addChar(139, 0x7fffdc, 23); + addChar(140, 0x7fffdd, 23); + addChar(141, 0x7fffde, 23); + addChar(142, 0xffffeb, 24); + addChar(143, 0x7fffdf, 23); + addChar(144, 0xffffec, 24); + addChar(145, 0xffffed, 24); + addChar(146, 0x3fffd7, 22); + addChar(147, 0x7fffe0, 23); + addChar(148, 0xffffee, 24); + addChar(149, 0x7fffe1, 23); + addChar(150, 0x7fffe2, 23); + addChar(151, 0x7fffe3, 23); + addChar(152, 0x7fffe4, 23); + addChar(153, 0x1fffdc, 21); + addChar(154, 0x3fffd8, 22); + addChar(155, 0x7fffe5, 23); + addChar(156, 0x3fffd9, 22); + addChar(157, 0x7fffe6, 23); + addChar(158, 0x7fffe7, 23); + addChar(159, 0xffffef, 24); + addChar(160, 0x3fffda, 22); + addChar(161, 0x1fffdd, 21); + addChar(162, 0xfffe9, 20); + addChar(163, 0x3fffdb, 22); + addChar(164, 0x3fffdc, 22); + addChar(165, 0x7fffe8, 23); + addChar(166, 0x7fffe9, 23); + addChar(167, 0x1fffde, 21); + addChar(168, 0x7fffea, 23); + addChar(169, 0x3fffdd, 22); + addChar(170, 0x3fffde, 22); + addChar(171, 0xfffff0, 24); + addChar(172, 0x1fffdf, 21); + addChar(173, 0x3fffdf, 22); + addChar(174, 0x7fffeb, 23); + addChar(175, 0x7fffec, 23); + addChar(176, 0x1fffe0, 21); + addChar(177, 0x1fffe1, 21); + addChar(178, 0x3fffe0, 22); + addChar(179, 0x1fffe2, 21); + addChar(180, 0x7fffed, 23); + addChar(181, 0x3fffe1, 22); + addChar(182, 0x7fffee, 23); + addChar(183, 0x7fffef, 23); + addChar(184, 0xfffea, 20); + addChar(185, 0x3fffe2, 22); + addChar(186, 0x3fffe3, 22); + addChar(187, 0x3fffe4, 22); + addChar(188, 0x7ffff0, 23); + addChar(189, 0x3fffe5, 22); + addChar(190, 0x3fffe6, 22); + addChar(191, 0x7ffff1, 23); + addChar(192, 0x3ffffe0, 26); + addChar(193, 0x3ffffe1, 26); + addChar(194, 0xfffeb, 20); + addChar(195, 0x7fff1, 19); + addChar(196, 0x3fffe7, 22); + addChar(197, 0x7ffff2, 23); + addChar(198, 0x3fffe8, 22); + addChar(199, 0x1ffffec, 25); + addChar(200, 0x3ffffe2, 26); + addChar(201, 0x3ffffe3, 26); + addChar(202, 0x3ffffe4, 26); + addChar(203, 0x7ffffde, 27); + addChar(204, 0x7ffffdf, 27); + addChar(205, 0x3ffffe5, 26); + addChar(206, 0xfffff1, 24); + addChar(207, 0x1ffffed, 25); + addChar(208, 0x7fff2, 19); + addChar(209, 0x1fffe3, 21); + addChar(210, 0x3ffffe6, 26); + addChar(211, 0x7ffffe0, 27); + addChar(212, 0x7ffffe1, 27); + addChar(213, 0x3ffffe7, 26); + addChar(214, 0x7ffffe2, 27); + addChar(215, 0xfffff2, 24); + addChar(216, 0x1fffe4, 21); + addChar(217, 0x1fffe5, 21); + addChar(218, 0x3ffffe8, 26); + addChar(219, 0x3ffffe9, 26); + addChar(220, 0xffffffd, 28); + addChar(221, 0x7ffffe3, 27); + addChar(222, 0x7ffffe4, 27); + addChar(223, 0x7ffffe5, 27); + addChar(224, 0xfffec, 20); + addChar(225, 0xfffff3, 24); + addChar(226, 0xfffed, 20); + addChar(227, 0x1fffe6, 21); + addChar(228, 0x3fffe9, 22); + addChar(229, 0x1fffe7, 21); + addChar(230, 0x1fffe8, 21); + addChar(231, 0x7ffff3, 23); + addChar(232, 0x3fffea, 22); + addChar(233, 0x3fffeb, 22); + addChar(234, 0x1ffffee, 25); + addChar(235, 0x1ffffef, 25); + addChar(236, 0xfffff4, 24); + addChar(237, 0xfffff5, 24); + addChar(238, 0x3ffffea, 26); + addChar(239, 0x7ffff4, 23); + addChar(240, 0x3ffffeb, 26); + addChar(241, 0x7ffffe6, 27); + addChar(242, 0x3ffffec, 26); + addChar(243, 0x3ffffed, 26); + addChar(244, 0x7ffffe7, 27); + addChar(245, 0x7ffffe8, 27); + addChar(246, 0x7ffffe9, 27); + addChar(247, 0x7ffffea, 27); + addChar(248, 0x7ffffeb, 27); + addChar(249, 0xffffffe, 28); + addChar(250, 0x7ffffec, 27); + addChar(251, 0x7ffffed, 27); + addChar(252, 0x7ffffee, 27); + addChar(253, 0x7ffffef, 27); + addChar(254, 0x7fffff0, 27); + addChar(255, 0x3ffffee, 26); + addEOS (256, EOS.code, EOS.length); + // @formatter:on + } + + + /** + * Calculates the number of bytes required to represent the given {@code + * CharSequence} with the Huffman coding. + * + * @param value + * characters + * + * @return number of bytes + * + * @throws NullPointerException + * if the value is null + */ + public int lengthOf(CharSequence value) { + return lengthOf(value, 0, value.length()); + } + + /** + * Calculates the number of bytes required to represent a subsequence of the + * given {@code CharSequence} with the Huffman coding. + * + * @param value + * characters + * @param start + * the start index, inclusive + * @param end + * the end index, exclusive + * + * @return number of bytes + * + * @throws NullPointerException + * if the value is null + * @throws IndexOutOfBoundsException + * if any invocation of {@code value.charAt(i)}, where + * {@code start <= i < end} would throw an IndexOutOfBoundsException + */ + public int lengthOf(CharSequence value, int start, int end) { + int len = 0; + for (int i = start; i < end; i++) { + char c = value.charAt(i); + len += INSTANCE.codeOf(c).length; + } + // Integer division with ceiling, assumption: + assert (len / 8 + (len % 8 != 0 ? 1 : 0)) == (len + 7) / 8 : len; + return (len + 7) / 8; + } + + private void addChar(int c, int code, int bitLength) { + addLeaf(c, code, bitLength, false); + codes[c] = new Code(code, bitLength); + } + + private void addEOS(int c, int code, int bitLength) { + addLeaf(c, code, bitLength, true); + codes[c] = new Code(code, bitLength); + } + + private void addLeaf(int c, int code, int bitLength, boolean isEOS) { + if (bitLength < 1) { + throw new IllegalArgumentException("bitLength < 1"); + } + Node curr = root; + for (int p = 1 << bitLength - 1; p != 0 && !curr.isLeaf(); p = p >> 1) { + curr.isEOSPath |= isEOS; // If it's already true, it can't become false + curr = curr.addChildIfAbsent(p & code); + } + curr.isEOSPath |= isEOS; // The last one needs to have this property as well + if (curr.isLeaf()) { + throw new IllegalStateException("Specified code is already taken"); + } + curr.setChar((char) c); + } + + private Code codeOf(char c) { + if (c > 255) { + throw new IllegalArgumentException("char=" + ((int) c)); + } + return codes[c]; + } + + // + // For debugging/testing purposes + // + Node getRoot() { + return root; + } + + // + // Guarantees: + // + // if (isLeaf() == true) => getChar() is a legal call + // if (isLeaf() == false) => getChild(i) is a legal call (though it can + // return null) + // + static class Node { + + Node left; + Node right; + boolean isEOSPath; + + boolean charIsSet; + char c; + + Node getChild(int selector) { + if (isLeaf()) { + throw new IllegalStateException("This is a leaf node"); + } + Node result = selector == 0 ? left : right; + if (result == null) { + throw new IllegalStateException(format( + "Node doesn't have a child (selector=%s)", selector)); + } + return result; + } + + boolean isLeaf() { + return charIsSet; + } + + char getChar() { + if (!isLeaf()) { + throw new IllegalStateException("This node is not a leaf node"); + } + return c; + } + + void setChar(char c) { + if (charIsSet) { + throw new IllegalStateException( + "This node has been taken already"); + } + if (left != null || right != null) { + throw new IllegalStateException("The node cannot be made " + + "a leaf as it's already has a child"); + } + this.c = c; + charIsSet = true; + } + + Node addChildIfAbsent(int i) { + if (charIsSet) { + throw new IllegalStateException("The node cannot have a child " + + "as it's already a leaf node"); + } + Node child; + if (i == 0) { + if ((child = left) == null) { + child = left = new Node(); + } + } else { + if ((child = right) == null) { + child = right = new Node(); + } + } + return child; + } + + @Override + public String toString() { + if (isLeaf()) { + if (isEOSPath) { + return "EOS"; + } else { + return format("char: (%3s) '%s'", (int) c, c); + } + } + return "/\\"; + } + } + + // TODO: value-based class? + // FIXME: can we re-use Node instead of this class? + private static final class Code { + + final int code; + final int length; + + private Code(int code, int length) { + this.code = code; + this.length = length; + } + + public int getCode() { + return code; + } + + public int getLength() { + return length; + } + + @Override + public String toString() { + long p = 1 << length; + return Long.toBinaryString(code + p).substring(1) + + ", length=" + length; + } + } +} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/QuickHuffman.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/QuickHuffman.java new file mode 100644 index 00000000000..633c9f05f88 --- /dev/null +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/QuickHuffman.java @@ -0,0 +1,826 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.net.http.hpack; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Objects; + +public final class QuickHuffman { + + /* + * Huffman codes for encoding. + * + * EOS will never be matched, since there is no symbol for it, thus no need + * to store it in the array. Thus, the length of the array is 256, not 257. + * Code information for each character is encoded as follows: + * + * MSB LSB + * +----------------+----------------+ + * |~code | length~| + * +----------------+----------------+ + * |<----- 32 ----->|<----- 32 ----->| + * |<------------- 64 -------------->| + * + * The leftmost 32 bits hold the code value. This value is aligned left + * (or MSB). The rightmost 32 bits hold the length of the code value. + * This length is aligned right (or LSB). + */ + private static final long[] codes = new long[256]; + + private static long codeValueOf(char c) { + return codes[c] & 0xffffffff00000000L; + } + + private static long codeLengthOf(char c) { + return codes[c] & 0x00000000ffffffffL; + } + + private static final int EOS_LENGTH = 30; + private static final int EOS_LSB = 0x3fffffff; + private static final long EOS_MSB = EOS_LSB << (64 - EOS_LENGTH); + + /* + * Huffman codes for decoding. + * + * Root node contains 257 descendant nodes, including EOS. + */ + private static final Node root; + + static { + TemporaryNode tmpRoot = new TemporaryNode(); + addChar(tmpRoot, 0, 0x1ff8, 13); + addChar(tmpRoot, 1, 0x7fffd8, 23); + addChar(tmpRoot, 2, 0xfffffe2, 28); + addChar(tmpRoot, 3, 0xfffffe3, 28); + addChar(tmpRoot, 4, 0xfffffe4, 28); + addChar(tmpRoot, 5, 0xfffffe5, 28); + addChar(tmpRoot, 6, 0xfffffe6, 28); + addChar(tmpRoot, 7, 0xfffffe7, 28); + addChar(tmpRoot, 8, 0xfffffe8, 28); + addChar(tmpRoot, 9, 0xffffea, 24); + addChar(tmpRoot, 10, 0x3ffffffc, 30); + addChar(tmpRoot, 11, 0xfffffe9, 28); + addChar(tmpRoot, 12, 0xfffffea, 28); + addChar(tmpRoot, 13, 0x3ffffffd, 30); + addChar(tmpRoot, 14, 0xfffffeb, 28); + addChar(tmpRoot, 15, 0xfffffec, 28); + addChar(tmpRoot, 16, 0xfffffed, 28); + addChar(tmpRoot, 17, 0xfffffee, 28); + addChar(tmpRoot, 18, 0xfffffef, 28); + addChar(tmpRoot, 19, 0xffffff0, 28); + addChar(tmpRoot, 20, 0xffffff1, 28); + addChar(tmpRoot, 21, 0xffffff2, 28); + addChar(tmpRoot, 22, 0x3ffffffe, 30); + addChar(tmpRoot, 23, 0xffffff3, 28); + addChar(tmpRoot, 24, 0xffffff4, 28); + addChar(tmpRoot, 25, 0xffffff5, 28); + addChar(tmpRoot, 26, 0xffffff6, 28); + addChar(tmpRoot, 27, 0xffffff7, 28); + addChar(tmpRoot, 28, 0xffffff8, 28); + addChar(tmpRoot, 29, 0xffffff9, 28); + addChar(tmpRoot, 30, 0xffffffa, 28); + addChar(tmpRoot, 31, 0xffffffb, 28); + addChar(tmpRoot, 32, 0x14, 6); + addChar(tmpRoot, 33, 0x3f8, 10); + addChar(tmpRoot, 34, 0x3f9, 10); + addChar(tmpRoot, 35, 0xffa, 12); + addChar(tmpRoot, 36, 0x1ff9, 13); + addChar(tmpRoot, 37, 0x15, 6); + addChar(tmpRoot, 38, 0xf8, 8); + addChar(tmpRoot, 39, 0x7fa, 11); + addChar(tmpRoot, 40, 0x3fa, 10); + addChar(tmpRoot, 41, 0x3fb, 10); + addChar(tmpRoot, 42, 0xf9, 8); + addChar(tmpRoot, 43, 0x7fb, 11); + addChar(tmpRoot, 44, 0xfa, 8); + addChar(tmpRoot, 45, 0x16, 6); + addChar(tmpRoot, 46, 0x17, 6); + addChar(tmpRoot, 47, 0x18, 6); + addChar(tmpRoot, 48, 0x0, 5); + addChar(tmpRoot, 49, 0x1, 5); + addChar(tmpRoot, 50, 0x2, 5); + addChar(tmpRoot, 51, 0x19, 6); + addChar(tmpRoot, 52, 0x1a, 6); + addChar(tmpRoot, 53, 0x1b, 6); + addChar(tmpRoot, 54, 0x1c, 6); + addChar(tmpRoot, 55, 0x1d, 6); + addChar(tmpRoot, 56, 0x1e, 6); + addChar(tmpRoot, 57, 0x1f, 6); + addChar(tmpRoot, 58, 0x5c, 7); + addChar(tmpRoot, 59, 0xfb, 8); + addChar(tmpRoot, 60, 0x7ffc, 15); + addChar(tmpRoot, 61, 0x20, 6); + addChar(tmpRoot, 62, 0xffb, 12); + addChar(tmpRoot, 63, 0x3fc, 10); + addChar(tmpRoot, 64, 0x1ffa, 13); + addChar(tmpRoot, 65, 0x21, 6); + addChar(tmpRoot, 66, 0x5d, 7); + addChar(tmpRoot, 67, 0x5e, 7); + addChar(tmpRoot, 68, 0x5f, 7); + addChar(tmpRoot, 69, 0x60, 7); + addChar(tmpRoot, 70, 0x61, 7); + addChar(tmpRoot, 71, 0x62, 7); + addChar(tmpRoot, 72, 0x63, 7); + addChar(tmpRoot, 73, 0x64, 7); + addChar(tmpRoot, 74, 0x65, 7); + addChar(tmpRoot, 75, 0x66, 7); + addChar(tmpRoot, 76, 0x67, 7); + addChar(tmpRoot, 77, 0x68, 7); + addChar(tmpRoot, 78, 0x69, 7); + addChar(tmpRoot, 79, 0x6a, 7); + addChar(tmpRoot, 80, 0x6b, 7); + addChar(tmpRoot, 81, 0x6c, 7); + addChar(tmpRoot, 82, 0x6d, 7); + addChar(tmpRoot, 83, 0x6e, 7); + addChar(tmpRoot, 84, 0x6f, 7); + addChar(tmpRoot, 85, 0x70, 7); + addChar(tmpRoot, 86, 0x71, 7); + addChar(tmpRoot, 87, 0x72, 7); + addChar(tmpRoot, 88, 0xfc, 8); + addChar(tmpRoot, 89, 0x73, 7); + addChar(tmpRoot, 90, 0xfd, 8); + addChar(tmpRoot, 91, 0x1ffb, 13); + addChar(tmpRoot, 92, 0x7fff0, 19); + addChar(tmpRoot, 93, 0x1ffc, 13); + addChar(tmpRoot, 94, 0x3ffc, 14); + addChar(tmpRoot, 95, 0x22, 6); + addChar(tmpRoot, 96, 0x7ffd, 15); + addChar(tmpRoot, 97, 0x3, 5); + addChar(tmpRoot, 98, 0x23, 6); + addChar(tmpRoot, 99, 0x4, 5); + addChar(tmpRoot, 100, 0x24, 6); + addChar(tmpRoot, 101, 0x5, 5); + addChar(tmpRoot, 102, 0x25, 6); + addChar(tmpRoot, 103, 0x26, 6); + addChar(tmpRoot, 104, 0x27, 6); + addChar(tmpRoot, 105, 0x6, 5); + addChar(tmpRoot, 106, 0x74, 7); + addChar(tmpRoot, 107, 0x75, 7); + addChar(tmpRoot, 108, 0x28, 6); + addChar(tmpRoot, 109, 0x29, 6); + addChar(tmpRoot, 110, 0x2a, 6); + addChar(tmpRoot, 111, 0x7, 5); + addChar(tmpRoot, 112, 0x2b, 6); + addChar(tmpRoot, 113, 0x76, 7); + addChar(tmpRoot, 114, 0x2c, 6); + addChar(tmpRoot, 115, 0x8, 5); + addChar(tmpRoot, 116, 0x9, 5); + addChar(tmpRoot, 117, 0x2d, 6); + addChar(tmpRoot, 118, 0x77, 7); + addChar(tmpRoot, 119, 0x78, 7); + addChar(tmpRoot, 120, 0x79, 7); + addChar(tmpRoot, 121, 0x7a, 7); + addChar(tmpRoot, 122, 0x7b, 7); + addChar(tmpRoot, 123, 0x7ffe, 15); + addChar(tmpRoot, 124, 0x7fc, 11); + addChar(tmpRoot, 125, 0x3ffd, 14); + addChar(tmpRoot, 126, 0x1ffd, 13); + addChar(tmpRoot, 127, 0xffffffc, 28); + addChar(tmpRoot, 128, 0xfffe6, 20); + addChar(tmpRoot, 129, 0x3fffd2, 22); + addChar(tmpRoot, 130, 0xfffe7, 20); + addChar(tmpRoot, 131, 0xfffe8, 20); + addChar(tmpRoot, 132, 0x3fffd3, 22); + addChar(tmpRoot, 133, 0x3fffd4, 22); + addChar(tmpRoot, 134, 0x3fffd5, 22); + addChar(tmpRoot, 135, 0x7fffd9, 23); + addChar(tmpRoot, 136, 0x3fffd6, 22); + addChar(tmpRoot, 137, 0x7fffda, 23); + addChar(tmpRoot, 138, 0x7fffdb, 23); + addChar(tmpRoot, 139, 0x7fffdc, 23); + addChar(tmpRoot, 140, 0x7fffdd, 23); + addChar(tmpRoot, 141, 0x7fffde, 23); + addChar(tmpRoot, 142, 0xffffeb, 24); + addChar(tmpRoot, 143, 0x7fffdf, 23); + addChar(tmpRoot, 144, 0xffffec, 24); + addChar(tmpRoot, 145, 0xffffed, 24); + addChar(tmpRoot, 146, 0x3fffd7, 22); + addChar(tmpRoot, 147, 0x7fffe0, 23); + addChar(tmpRoot, 148, 0xffffee, 24); + addChar(tmpRoot, 149, 0x7fffe1, 23); + addChar(tmpRoot, 150, 0x7fffe2, 23); + addChar(tmpRoot, 151, 0x7fffe3, 23); + addChar(tmpRoot, 152, 0x7fffe4, 23); + addChar(tmpRoot, 153, 0x1fffdc, 21); + addChar(tmpRoot, 154, 0x3fffd8, 22); + addChar(tmpRoot, 155, 0x7fffe5, 23); + addChar(tmpRoot, 156, 0x3fffd9, 22); + addChar(tmpRoot, 157, 0x7fffe6, 23); + addChar(tmpRoot, 158, 0x7fffe7, 23); + addChar(tmpRoot, 159, 0xffffef, 24); + addChar(tmpRoot, 160, 0x3fffda, 22); + addChar(tmpRoot, 161, 0x1fffdd, 21); + addChar(tmpRoot, 162, 0xfffe9, 20); + addChar(tmpRoot, 163, 0x3fffdb, 22); + addChar(tmpRoot, 164, 0x3fffdc, 22); + addChar(tmpRoot, 165, 0x7fffe8, 23); + addChar(tmpRoot, 166, 0x7fffe9, 23); + addChar(tmpRoot, 167, 0x1fffde, 21); + addChar(tmpRoot, 168, 0x7fffea, 23); + addChar(tmpRoot, 169, 0x3fffdd, 22); + addChar(tmpRoot, 170, 0x3fffde, 22); + addChar(tmpRoot, 171, 0xfffff0, 24); + addChar(tmpRoot, 172, 0x1fffdf, 21); + addChar(tmpRoot, 173, 0x3fffdf, 22); + addChar(tmpRoot, 174, 0x7fffeb, 23); + addChar(tmpRoot, 175, 0x7fffec, 23); + addChar(tmpRoot, 176, 0x1fffe0, 21); + addChar(tmpRoot, 177, 0x1fffe1, 21); + addChar(tmpRoot, 178, 0x3fffe0, 22); + addChar(tmpRoot, 179, 0x1fffe2, 21); + addChar(tmpRoot, 180, 0x7fffed, 23); + addChar(tmpRoot, 181, 0x3fffe1, 22); + addChar(tmpRoot, 182, 0x7fffee, 23); + addChar(tmpRoot, 183, 0x7fffef, 23); + addChar(tmpRoot, 184, 0xfffea, 20); + addChar(tmpRoot, 185, 0x3fffe2, 22); + addChar(tmpRoot, 186, 0x3fffe3, 22); + addChar(tmpRoot, 187, 0x3fffe4, 22); + addChar(tmpRoot, 188, 0x7ffff0, 23); + addChar(tmpRoot, 189, 0x3fffe5, 22); + addChar(tmpRoot, 190, 0x3fffe6, 22); + addChar(tmpRoot, 191, 0x7ffff1, 23); + addChar(tmpRoot, 192, 0x3ffffe0, 26); + addChar(tmpRoot, 193, 0x3ffffe1, 26); + addChar(tmpRoot, 194, 0xfffeb, 20); + addChar(tmpRoot, 195, 0x7fff1, 19); + addChar(tmpRoot, 196, 0x3fffe7, 22); + addChar(tmpRoot, 197, 0x7ffff2, 23); + addChar(tmpRoot, 198, 0x3fffe8, 22); + addChar(tmpRoot, 199, 0x1ffffec, 25); + addChar(tmpRoot, 200, 0x3ffffe2, 26); + addChar(tmpRoot, 201, 0x3ffffe3, 26); + addChar(tmpRoot, 202, 0x3ffffe4, 26); + addChar(tmpRoot, 203, 0x7ffffde, 27); + addChar(tmpRoot, 204, 0x7ffffdf, 27); + addChar(tmpRoot, 205, 0x3ffffe5, 26); + addChar(tmpRoot, 206, 0xfffff1, 24); + addChar(tmpRoot, 207, 0x1ffffed, 25); + addChar(tmpRoot, 208, 0x7fff2, 19); + addChar(tmpRoot, 209, 0x1fffe3, 21); + addChar(tmpRoot, 210, 0x3ffffe6, 26); + addChar(tmpRoot, 211, 0x7ffffe0, 27); + addChar(tmpRoot, 212, 0x7ffffe1, 27); + addChar(tmpRoot, 213, 0x3ffffe7, 26); + addChar(tmpRoot, 214, 0x7ffffe2, 27); + addChar(tmpRoot, 215, 0xfffff2, 24); + addChar(tmpRoot, 216, 0x1fffe4, 21); + addChar(tmpRoot, 217, 0x1fffe5, 21); + addChar(tmpRoot, 218, 0x3ffffe8, 26); + addChar(tmpRoot, 219, 0x3ffffe9, 26); + addChar(tmpRoot, 220, 0xffffffd, 28); + addChar(tmpRoot, 221, 0x7ffffe3, 27); + addChar(tmpRoot, 222, 0x7ffffe4, 27); + addChar(tmpRoot, 223, 0x7ffffe5, 27); + addChar(tmpRoot, 224, 0xfffec, 20); + addChar(tmpRoot, 225, 0xfffff3, 24); + addChar(tmpRoot, 226, 0xfffed, 20); + addChar(tmpRoot, 227, 0x1fffe6, 21); + addChar(tmpRoot, 228, 0x3fffe9, 22); + addChar(tmpRoot, 229, 0x1fffe7, 21); + addChar(tmpRoot, 230, 0x1fffe8, 21); + addChar(tmpRoot, 231, 0x7ffff3, 23); + addChar(tmpRoot, 232, 0x3fffea, 22); + addChar(tmpRoot, 233, 0x3fffeb, 22); + addChar(tmpRoot, 234, 0x1ffffee, 25); + addChar(tmpRoot, 235, 0x1ffffef, 25); + addChar(tmpRoot, 236, 0xfffff4, 24); + addChar(tmpRoot, 237, 0xfffff5, 24); + addChar(tmpRoot, 238, 0x3ffffea, 26); + addChar(tmpRoot, 239, 0x7ffff4, 23); + addChar(tmpRoot, 240, 0x3ffffeb, 26); + addChar(tmpRoot, 241, 0x7ffffe6, 27); + addChar(tmpRoot, 242, 0x3ffffec, 26); + addChar(tmpRoot, 243, 0x3ffffed, 26); + addChar(tmpRoot, 244, 0x7ffffe7, 27); + addChar(tmpRoot, 245, 0x7ffffe8, 27); + addChar(tmpRoot, 246, 0x7ffffe9, 27); + addChar(tmpRoot, 247, 0x7ffffea, 27); + addChar(tmpRoot, 248, 0x7ffffeb, 27); + addChar(tmpRoot, 249, 0xffffffe, 28); + addChar(tmpRoot, 250, 0x7ffffec, 27); + addChar(tmpRoot, 251, 0x7ffffed, 27); + addChar(tmpRoot, 252, 0x7ffffee, 27); + addChar(tmpRoot, 253, 0x7ffffef, 27); + addChar(tmpRoot, 254, 0x7fffff0, 27); + addChar(tmpRoot, 255, 0x3ffffee, 26); + addEOS (tmpRoot, 256, EOS_LSB, EOS_LENGTH); + + // The difference in performance can always be checked by not using + // the immutable trie: + // root = tmpRoot; + root = ImmutableNode.copyOf(tmpRoot); + } + + private QuickHuffman() { } + + private static void addChar(Node root, int symbol, int code, int bitLength) + { + addLeaf(root, (char) symbol, code, bitLength, false); + long value = ((long) code) << (64 - bitLength); // re-align MSB <- LSB + codes[symbol] = value | bitLength; + } + + private static void addEOS(Node root, int symbol, int code, int bitLength) + { + addLeaf(root, (char) symbol, code, bitLength, true); + } + + private static void addLeaf(Node root, + char symbol, + int code, + int bitLength, + boolean isEOS) + { + assert 0 < bitLength && bitLength <= 32 : bitLength; + Node curr = root; + int nBytes = bytesForBits(bitLength); + // The number of bits the code needs to be shifted to the left in order + // to align with the byte #nBytes boundary: + int align = (nBytes << 3) - bitLength; + code <<= align; + // descend the trie until the last element + int l = 0; + for (int i = 0, probe = 0xff << ((nBytes - 1) << 3); + i < nBytes - 1; + i++, probe >>>= 8) + { + curr.setEOSPath(curr.isEOSPath() | isEOS); + int idx = (code & probe) >>> ((nBytes - 1 - i) << 3); + curr = curr.getOrCreateChild(idx); + curr.setLength(8); + l += 8; + } + // Assign the same char to all byte variants. For example, if the code + // and its length are 00011b and 5 respectively (letter 'a') then, in + // order to be able to match any byte starting with 00011b prefix, + // the following nodes need to be created: + // + // 00011000b, 00011001b, 00011010b, 00011011b, 00011100b, 00011101b, + // 00011110b and 00011111b + int idx = code & 0xff; + curr.setEOSPath(curr.isEOSPath() | isEOS); + for (int i = 0; i < (1 << align); i++) { + Node child = curr.getOrCreateChild(idx | i); + child.setSymbol(symbol); + child.setEOSPath(child.isEOSPath() | isEOS); + child.setLength(bitLength - l); + } + } + + /* + * A node in the Huffman trie. + */ + interface Node { + + boolean isEOSPath(); + + void setEOSPath(boolean value); + + boolean isLeaf(); + + Node getChild(int index); + + Node getOrCreateChild(int index); + + Node[] getChildren(); + + char getSymbol(); + + void setSymbol(char symbol); + + int getLength(); + + void setLength(int value); + } + + /* + * Mutable nodes used for initial construction of the Huffman trie. + * (These nodes are perfectly ok to be used after that.) + */ + static final class TemporaryNode implements Node { + + private char symbol; + private boolean eosPath; + private TemporaryNode[] children; + private int length; + + @Override + public TemporaryNode getOrCreateChild(int index) { + ensureChildrenExist(); + if (children[index] == null) { + children[index] = new TemporaryNode(); + } + return children[index]; + } + + private void ensureChildrenExist() { + if (children == null) { + children = new TemporaryNode[256]; + } + } + + @Override + public boolean isLeaf() { + return children == null; + } + + @Override + public boolean isEOSPath() { + return eosPath; + } + + @Override + public void setEOSPath(boolean value) { + eosPath = value; + } + + @Override + public TemporaryNode getChild(int index) { + ensureChildrenExist(); + return children[index]; + } + + @Override + public Node[] getChildren() { + if (children == null) { + return new Node[0]; + } + return children; + } + + @Override + public char getSymbol() { + return symbol; + } + + @Override + public int getLength() { + return length; + } + + @Override + public void setSymbol(char value) { + this.symbol = value; + } + + @Override + public void setLength(int value) { + this.length = value; + } + } + + /* + * Immutable node used to construct traversal-only Huffman trie. + * + * Once the trie has been built, the support of modifications is no longer + * required. An immutable trie should be used. Not only it will help to + * catch possible bugs, but hopefully speedup the traversal operations. + */ + static final class ImmutableNode implements Node { + + private final char symbol; + private final boolean eosPath; + private final int length; + private final List children; + + public static ImmutableNode copyOf(Node node) { + if (node.isLeaf()) { + return new ImmutableNode(node.getSymbol(), node.isEOSPath(), + node.getLength()); + } + Node[] children = node.getChildren(); + ImmutableNode[] immutableChildren = new ImmutableNode[children.length]; + for (int i = 0; i < children.length; i++) { + immutableChildren[i] = copyOf(children[i]); + } + return new ImmutableNode(node.isEOSPath(), node.getLength(), + immutableChildren); + } + + /* Creates a leaf node */ + private ImmutableNode(char symbol, + boolean eosPath, + int length) { + this.symbol = symbol; + this.eosPath = eosPath; + this.length = length; + this.children = List.of(); + } + + /* Creates a node with children */ + private ImmutableNode(boolean eosPath, + int length, + ImmutableNode[] children) + { + this.symbol = 0; + this.eosPath = eosPath; + this.length = length; + if (children.length == 0) { + throw new IllegalArgumentException(); + } + // A list produced by List.of should not be slower than array for + // accessing elements by index, and hopefully use additional + // optimizations (e.g. jdk.internal.vm.annotation.Stable) + this.children = List.of(children); + } + + @Override + public boolean isLeaf() { + return children.isEmpty(); + } + + @Override + public boolean isEOSPath() { + return eosPath; + } + + @Override + public void setEOSPath(boolean value) { + throw new UnsupportedOperationException(); + } + + @Override + public ImmutableNode getChild(int index) { + return children.get(index); + } + + @Override + public ImmutableNode getOrCreateChild(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public ImmutableNode[] getChildren() { + // This method is not expected to be called on an immutable node. + // If it is called, it requires some investigation. + throw new UnsupportedOperationException(); + } + + @Override + public char getSymbol() { + return symbol; + } + + @Override + public void setSymbol(char symbol) { + throw new UnsupportedOperationException(); + } + + @Override + public int getLength() { + return length; + } + + @Override + public void setLength(int value) { + throw new UnsupportedOperationException(); + } + } + + static final class Reader implements Huffman.Reader { + + private Node curr = root; // current position in the trie + private long buffer; // bits left from the previous match (aligned to the left, or MSB) + private int bufferLen; // number of bits in the buffer + private int len; // length (in bits) of path to curr + private boolean done; + + @Override + public void read(ByteBuffer source, + Appendable destination, + boolean isLast) throws IOException + { + read(source, destination, true, isLast); + } + + @Override + public void reset() { + curr = root; + len = 0; + buffer = 0; + bufferLen = 0; + done = false; + } + + @SuppressWarnings("fallthrough") + void read(ByteBuffer source, + Appendable destination, + boolean reportEOS, /* reportEOS is exposed for tests */ + boolean isLast) throws IOException + { + while (!done) { + // read as much as possible (up to 8 bytes) + int remaining = source.remaining(); + int nBytes = Math.min((64 - bufferLen) >> 3, remaining); + switch (nBytes) { + case 0: + break; + case 3: + readByte(source); + case 2: + readByte(source); + case 1: + readByte(source); + break; + case 7: + readByte(source); + case 6: + readByte(source); + case 5: + readByte(source); + case 4: + readInt(source); + break; + case 8: + readLong(source); + break; + default: + throw new InternalError(String.valueOf(nBytes)); + } + // write as much as possible + while (true) { + if (bufferLen < 8) { + if (nBytes < remaining) { // read again + break; + } else if (!isLast) { // exit the method to accept more input + return; + } else if (bufferLen > 0) { // no more data is expected, pad + // (this padding may be done more than once) + buffer |= ((0xff00000000000000L >>> bufferLen) + & 0xff00000000000000L); + // do not update bufferLen, since all those ones are + // synthetic and are appended merely for the sake of + // lookup + } else { + done = true; + break; + } + } + int idx = (int) (buffer >>> 56); + Node node = curr.getChild(idx); + if (node == null) { // TODO: TEST + throw new IOException("Unexpected byte"); + } + if (node.isLeaf()) { + if (node.getLength() > bufferLen) { // matched more than we actually could (because of padding) + throw new IOException( + "Not a EOS prefix padding or unexpected end of data"); + } + if (reportEOS && node.isEOSPath()) { + throw new IOException("Encountered EOS"); + } + destination.append(node.getSymbol()); + curr = root; + len = 0; + } else { + curr = node; + // because of the padding, we can't match more bits than + // there are currently in the buffer + len += Math.min(bufferLen, node.getLength()); + } + buffer <<= node.getLength(); + bufferLen -= node.getLength(); + } + if (done && (curr.isEOSPath() && len > 7)) { + throw new IOException( + "Padding is too long (len=" + len + ") " + + "or unexpected end of data"); + } + } + } + + private void readLong(ByteBuffer source) { + buffer = source.getLong(); + bufferLen = 64; + } + + private void readInt(ByteBuffer source) { + long b; + b = source.getInt() & 0x00000000ffffffffL; + buffer |= (b << (32 - bufferLen)); + bufferLen += 32; + } + + private void readByte(ByteBuffer source) { + long b = source.get() & 0x00000000000000ffL; + buffer |= (b << (56 - bufferLen)); + bufferLen += 8; + } + } + + static final class Writer implements Huffman.Writer { + + private CharSequence source; + private boolean padded; + private int pos; + private int end; + private long buffer; + private int bufferLen; + + @Override + public QuickHuffman.Writer from(CharSequence input, int start, int end) { + Objects.checkFromToIndex(start, end, input.length()); + this.pos = start; + this.end = end; + this.source = input; + return this; + } + + @SuppressWarnings("fallthrough") + @Override + public boolean write(ByteBuffer destination) { + while (true) { + while (bufferLen < 32 && pos < end) { + char c = source.charAt(pos++); + buffer |= (codeValueOf(c) >>> bufferLen); // append + bufferLen += codeLengthOf(c); + } + if (bufferLen == 0) { + return true; + } + if (pos >= end && !padded) { // no more chars, pad + padded = true; + buffer |= (EOS_MSB >>> bufferLen); + bufferLen = bytesForBits(bufferLen) << 3; + } + // The number of bytes that can be written at once + // (calculating in bytes, not bits, since + // destination.remaining() * 8 might overflow) + + int nBytes = Math.min(bytesForBits(bufferLen), destination.remaining()); // ceil? + switch (nBytes) { + case 0: + return false; + case 1: + case 2: + case 3: + destination.put((byte) (buffer >>> 56)); + buffer <<= 8; + bufferLen -= 8; + break; + default: + destination.putInt((int) (buffer >>> 32)); + buffer <<= 32; + bufferLen -= 32; + break; + } + } + } + + @Override + public QuickHuffman.Writer reset() { + source = null; + buffer = 0; + bufferLen = 0; + end = 0; + pos = 0; + padded = false; + return this; + } + + @Override + public int lengthOf(CharSequence value, int start, int end) { + int len = 0; + for (int i = start; i < end; i++) { + char c = value.charAt(i); + len += codeLengthOf(c); + } + return bytesForBits(len); + } + } + + /* + * Returns the number of bytes the given number of bits constitute. + */ + private static int bytesForBits(int n) { + assert (n / 8 + (n % 8 != 0 ? 1 : 0)) == (n + 7) / 8 + && (n + 7) / 8 == ((n + 7) >> 3) : n; + return (n + 7) >> 3; + } +} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/SimpleHeaderTable.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/SimpleHeaderTable.java index 4a0b4c65d57..a39729d2a44 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/SimpleHeaderTable.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/SimpleHeaderTable.java @@ -28,6 +28,7 @@ import jdk.internal.net.http.hpack.HPACK.Logger; import java.util.NoSuchElementException; +import static jdk.internal.net.http.common.Utils.pow2Size; import static jdk.internal.net.http.hpack.HPACK.Logger.Level.EXTRA; import static jdk.internal.net.http.hpack.HPACK.Logger.Level.NORMAL; import static java.lang.String.format; @@ -306,8 +307,8 @@ class SimpleHeaderTable { Object[] elements; CircularBuffer(int capacity) { - this.capacity = capacity; - elements = new Object[capacity]; + this.capacity = pow2Size(capacity); + elements = new Object[this.capacity]; } void add(E elem) { @@ -316,7 +317,7 @@ class SimpleHeaderTable { format("No room for '%s': capacity=%s", elem, capacity)); } elements[head] = elem; - head = (head + 1) % capacity; + head = (head + 1) & (capacity - 1); size++; } @@ -327,7 +328,7 @@ class SimpleHeaderTable { } E elem = (E) elements[tail]; elements[tail] = null; - tail = (tail + 1) % capacity; + tail = (tail + 1) & (capacity - 1); size--; return elem; } @@ -339,7 +340,7 @@ class SimpleHeaderTable { format("0 <= index <= capacity: index=%s, capacity=%s", index, capacity)); } - int idx = (tail + (size - index - 1)) % capacity; + int idx = (tail + (size - index - 1)) & (capacity - 1); return (E) elements[idx]; } @@ -350,7 +351,8 @@ class SimpleHeaderTable { newCapacity, size)); } - Object[] newElements = new Object[newCapacity]; + int capacity = pow2Size(newCapacity); + Object[] newElements = new Object[capacity]; if (tail < head || size == 0) { System.arraycopy(elements, tail, newElements, 0, size); @@ -362,7 +364,7 @@ class SimpleHeaderTable { elements = newElements; tail = 0; head = size; - this.capacity = newCapacity; + this.capacity = capacity; } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringReader.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringReader.java index 48e5868c416..62a4d176fcb 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringReader.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringReader.java @@ -44,7 +44,7 @@ final class StringReader { private static final int DONE = 4; private final IntegerReader intReader = new IntegerReader(); - private final Huffman.Reader huffmanReader = new Huffman.Reader(); + private final Huffman.Reader huffmanReader = new QuickHuffman.Reader(); private final ISO_8859_1.Reader plainReader = new ISO_8859_1.Reader(); private int state = NEW; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringWriter.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringWriter.java index f7102e52caf..594fd1782d1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringWriter.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/StringWriter.java @@ -52,7 +52,7 @@ final class StringWriter { private static final int DONE = 4; private final IntegerWriter intWriter = new IntegerWriter(); - private final Huffman.Writer huffmanWriter = new Huffman.Writer(); + private final Huffman.Writer huffmanWriter = new QuickHuffman.Writer(); private final ISO_8859_1.Writer plainWriter = new ISO_8859_1.Writer(); private int state = NEW; @@ -76,7 +76,7 @@ final class StringWriter { intWriter.configure(end - start, 7, 0b0000_0000); } else { huffmanWriter.from(input, start, end); - intWriter.configure(Huffman.INSTANCE.lengthOf(input, start, end), + intWriter.configure(huffmanWriter.lengthOf(input, start, end), 7, 0b1000_0000); } diff --git a/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java b/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java index 06baf683915..397e2a519fb 100644 --- a/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java +++ b/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java @@ -40,8 +40,8 @@ import static java.lang.System.err; /* * @test * @bug 8187503 - * @summary An example on how to read a response body with InputStream... - * @run main/othervm -Dtest.debug=true BodyProcessorInputStreamTest + * @summary An example on how to read a response body with InputStream. + * @run main/manual -Dtest.debug=true BodyProcessorInputStreamTest * @author daniel fuchs */ public class BodyProcessorInputStreamTest { diff --git a/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java b/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java index cd75c0fb0ff..36f70885e34 100644 --- a/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java +++ b/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java @@ -177,6 +177,8 @@ public class DependentPromiseActionsTest implements HttpServerAdapters { }; } + enum SubscriberType {EAGER, LAZZY} + static final class SemaphoreStallerSupplier implements Supplier { @Override @@ -291,7 +293,8 @@ public class DependentPromiseActionsTest implements HttpServerAdapters { String test = format("testAsStringAsync(%s, %b, %s)", uri, sameClient, stallers); testDependent(test, uri, sameClient, BodyHandlers::ofString, - this::finish, this::extractString, stallers); + this::finish, this::extractString, stallers, + SubscriberType.EAGER); } @Test(dataProvider = "variants") @@ -303,7 +306,8 @@ public class DependentPromiseActionsTest implements HttpServerAdapters { String test = format("testAsLinesAsync(%s, %b, %s)", uri, sameClient, stallers); testDependent(test, uri, sameClient, BodyHandlers::ofLines, - this::finish, this::extractStream, stallers); + this::finish, this::extractStream, stallers, + SubscriberType.LAZZY); } @Test(dataProvider = "variants") @@ -315,19 +319,22 @@ public class DependentPromiseActionsTest implements HttpServerAdapters { String test = format("testAsInputStreamAsync(%s, %b, %s)", uri, sameClient, stallers); testDependent(test, uri, sameClient, BodyHandlers::ofInputStream, - this::finish, this::extractInputStream, stallers); + this::finish, this::extractInputStream, stallers, + SubscriberType.LAZZY); } private void testDependent(String name, String uri, boolean sameClient, Supplier> handlers, Finisher finisher, Extractor extractor, - Supplier stallers) + Supplier stallers, + SubscriberType subscriberType) throws Exception { out.printf("%n%s%s%n", now(), name); try { - testDependent(uri, sameClient, handlers, finisher, extractor, stallers); + testDependent(uri, sameClient, handlers, finisher, + extractor, stallers, subscriberType); } catch (Error | Exception x) { FAILURES.putIfAbsent(name, x); throw x; @@ -338,7 +345,8 @@ public class DependentPromiseActionsTest implements HttpServerAdapters { Supplier> handlers, Finisher finisher, Extractor extractor, - Supplier stallers) + Supplier stallers, + SubscriberType subscriberType) throws Exception { HttpClient client = null; @@ -355,7 +363,7 @@ public class DependentPromiseActionsTest implements HttpServerAdapters { System.out.println("try stalling in " + where); CompletableFuture> responseCF = client.sendAsync(req, handler, promiseHandler); - assert !responseCF.isDone(); + assert subscriberType == SubscriberType.LAZZY || !responseCF.isDone(); finisher.finish(where, responseCF, promiseHandler, extractor); } } diff --git a/test/jdk/java/net/httpclient/EscapedOctetsInURI.java b/test/jdk/java/net/httpclient/EscapedOctetsInURI.java index a82ca0acffc..1495bb78667 100644 --- a/test/jdk/java/net/httpclient/EscapedOctetsInURI.java +++ b/test/jdk/java/net/httpclient/EscapedOctetsInURI.java @@ -116,6 +116,8 @@ public class EscapedOctetsInURI { @Test(dataProvider = "variants") void test(String uriString, boolean sameClient) throws Exception { + System.out.println("\n--- Starting "); + // The single-argument factory requires any illegal characters in its // argument to be quoted and preserves any escaped octets and other // characters that are present. @@ -146,6 +148,7 @@ public class EscapedOctetsInURI { @Test(dataProvider = "variants") void testAsync(String uriString, boolean sameClient) { + System.out.println("\n--- Starting "); URI uri = URI.create(uriString); HttpClient client = null; diff --git a/test/jdk/java/net/httpclient/HttpInputStreamTest.java b/test/jdk/java/net/httpclient/HttpInputStreamTest.java index 710b6ade80b..fab70974aac 100644 --- a/test/jdk/java/net/httpclient/HttpInputStreamTest.java +++ b/test/jdk/java/net/httpclient/HttpInputStreamTest.java @@ -46,8 +46,8 @@ import static java.lang.System.err; /* * @test - * @summary An example on how to read a response body with InputStream... - * @run main/othervm -Dtest.debug=true HttpInputStreamTest + * @summary An example on how to read a response body with InputStream. + * @run main/manual -Dtest.debug=true HttpInputStreamTest * @author daniel fuchs */ public class HttpInputStreamTest { diff --git a/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java b/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java new file mode 100644 index 00000000000..f9de44c05f9 --- /dev/null +++ b/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Verify that non-US-ASCII chars are replaced with a sequence of + * escaped octets that represent that char in the UTF-8 character set. + * @bug 8201238 + * @modules java.base/sun.net.www.http + * java.net.http/jdk.internal.net.http.common + * java.net.http/jdk.internal.net.http.frame + * java.net.http/jdk.internal.net.http.hpack + * java.logging + * jdk.httpserver + * @library /lib/testlibrary http2/server + * @build Http2TestServer + * @build jdk.testlibrary.SimpleSSLContext + * @compile -encoding utf-8 NonAsciiCharsInURI.java + * @run testng/othervm + * -Djdk.httpclient.HttpClient.log=reqeusts,headers + * NonAsciiCharsInURI + */ + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import javax.net.ssl.SSLContext; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.testlibrary.SimpleSSLContext; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.lang.System.err; +import static java.lang.System.out; +import static java.nio.charset.StandardCharsets.US_ASCII; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.testng.Assert.assertEquals; + +public class NonAsciiCharsInURI implements HttpServerAdapters { + + SSLContext sslContext; + HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ] + HttpTestServer httpsTestServer; // HTTPS/1.1 + HttpTestServer http2TestServer; // HTTP/2 ( h2c ) + HttpTestServer https2TestServer; // HTTP/2 ( h2 ) + String httpURI; + String httpsURI; + String http2URI; + String https2URI; + + // € = '\u20AC' => 0xE20x820xAC + static final String[][] pathsAndQueryStrings = new String[][] { + // partial-path + { "/001/plain" }, + { "/002/plain?plainQuery" }, + { "/003/withEuroSymbol/€" }, + { "/004/withEuroSymbol/€?euroSymbol=€" }, + { "/005/wiki/エリザベス1世_(イングランド女王)" }, + { "/006/x?url=https://ja.wikipedia.org/wiki/エリザベス1世_(イングランド女王)" }, + }; + + @DataProvider(name = "variants") + public Object[][] variants() { + List list = new ArrayList<>(); + + for (boolean sameClient : new boolean[] { false, true }) { + Arrays.asList(pathsAndQueryStrings).stream() + .map(e -> new Object[] {httpURI + e[0], sameClient}) + .forEach(list::add); + Arrays.asList(pathsAndQueryStrings).stream() + .map(e -> new Object[] {httpsURI + e[0], sameClient}) + .forEach(list::add); + Arrays.asList(pathsAndQueryStrings).stream() + .map(e -> new Object[] {http2URI + e[0], sameClient}) + .forEach(list::add); + Arrays.asList(pathsAndQueryStrings).stream() + .map(e -> new Object[] {https2URI + e[0], sameClient}) + .forEach(list::add); + } + return list.stream().toArray(Object[][]::new); + } + + static final int ITERATION_COUNT = 3; // checks upgrade and re-use + + @Test(dataProvider = "variants") + void test(String uriString, boolean sameClient) throws Exception { + out.println("\n--- Starting "); + // The single-argument factory requires any illegal characters in its + // argument to be quoted and preserves any escaped octets and other + // characters that are present. + URI uri = URI.create(uriString); + + HttpClient client = null; + for (int i=0; i< ITERATION_COUNT; i++) { + if (!sameClient || client == null) + client = HttpClient.newBuilder() + .proxy(NO_PROXY) + .sslContext(sslContext) + .build(); + + HttpRequest request = HttpRequest.newBuilder(uri).build(); + HttpResponse resp = client.send(request, BodyHandlers.ofString()); + + out.println("Got response: " + resp); + out.println("Got body: " + resp.body()); + assertEquals(resp.statusCode(), 200, + "Expected 200, got:" + resp.statusCode()); + + // the response body should contain the toASCIIString + // representation of the URI + String expectedURIString = uri.toASCIIString(); + if (!expectedURIString.contains(resp.body())) { + err.println("Test failed: " + resp); + throw new AssertionError(expectedURIString + + " does not contain '" + resp.body() + "'"); + } else { + out.println("Found expected " + resp.body() + " in " + expectedURIString); + } + } + } + + @Test(dataProvider = "variants") + void testAsync(String uriString, boolean sameClient) { + out.println("\n--- Starting "); + URI uri = URI.create(uriString); + + HttpClient client = null; + for (int i=0; i< ITERATION_COUNT; i++) { + if (!sameClient || client == null) + client = HttpClient.newBuilder() + .proxy(NO_PROXY) + .sslContext(sslContext) + .build(); + + HttpRequest request = HttpRequest.newBuilder(uri).build(); + + client.sendAsync(request, BodyHandlers.ofString()) + .thenApply(response -> { + out.println("Got response: " + response); + out.println("Got body: " + response.body()); + assertEquals(response.statusCode(), 200); + return response.body(); }) + .thenAccept(body -> { + // the response body should contain the toASCIIString + // representation of the URI + String expectedURIString = uri.toASCIIString(); + if (!expectedURIString.contains(body)) { + err.println("Test failed: " + body); + throw new AssertionError(expectedURIString + + " does not contain '" + body + "'"); + } else { + out.println("Found expected " + body + " in " + + expectedURIString); + } }) + .join(); + } + } + + static String serverAuthority(HttpTestServer server) { + return InetAddress.getLoopbackAddress().getHostName() + ":" + + server.getAddress().getPort(); + } + + @BeforeTest + public void setup() throws Exception { + sslContext = new SimpleSSLContext().get(); + if (sslContext == null) + throw new AssertionError("Unexpected null sslContext"); + + HttpTestHandler handler = new HttpUriStringHandler(); + InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + httpTestServer = HttpTestServer.of(HttpServer.create(sa, 0)); + httpTestServer.addHandler(handler, "/http1"); + httpURI = "http://" + serverAuthority(httpTestServer) + "/http1"; + + HttpsServer httpsServer = HttpsServer.create(sa, 0); + httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); + httpsTestServer = HttpTestServer.of(httpsServer); + httpsTestServer.addHandler(handler, "/https1"); + httpsURI = "https://" + serverAuthority(httpsTestServer) + "/https1"; + + http2TestServer = HttpTestServer.of(new Http2TestServer("localhost", false, 0)); + http2TestServer.addHandler(handler, "/http2"); + http2URI = "http://" + http2TestServer.serverAuthority() + "/http2"; + + https2TestServer = HttpTestServer.of(new Http2TestServer("localhost", true, 0)); + https2TestServer.addHandler(handler, "/https2"); + https2URI = "https://" + https2TestServer.serverAuthority() + "/https2"; + + httpTestServer.start(); + httpsTestServer.start(); + http2TestServer.start(); + https2TestServer.start(); + } + + @AfterTest + public void teardown() throws Exception { + httpTestServer.stop(); + httpsTestServer.stop(); + http2TestServer.stop(); + https2TestServer.stop(); + } + + /** A handler that returns, as its body, the exact received request URI. */ + static class HttpUriStringHandler implements HttpTestHandler { + @Override + public void handle(HttpTestExchange t) throws IOException { + String uri = t.getRequestURI().toString(); + out.println("Http1UriStringHandler received, uri: " + uri); + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + is.readAllBytes(); + byte[] bytes = uri.getBytes(US_ASCII); + t.sendResponseHeaders(200, bytes.length); + os.write(bytes); + } + } + } +} diff --git a/test/jdk/java/net/httpclient/ProxyServer.java b/test/jdk/java/net/httpclient/ProxyServer.java index b931a369610..96b1dc359ea 100644 --- a/test/jdk/java/net/httpclient/ProxyServer.java +++ b/test/jdk/java/net/httpclient/ProxyServer.java @@ -73,12 +73,10 @@ public class ProxyServer extends Thread implements Closeable { */ public void close() throws IOException { if (debug) System.out.println("Proxy: closing"); - done = true; + done = true; listener.close(); for (Connection c : connections) { - if (c.running()) { - c.close(); - } + c.close(); } } @@ -179,7 +177,9 @@ public class ProxyServer extends Thread implements Closeable { return out.isAlive() || in.isAlive(); } - public void close() throws IOException { + private volatile boolean closing; + public synchronized void close() throws IOException { + closing = true; if (debug) System.out.println("Closing connection (proxy)"); if (serverSocket != null) serverSocket.close(); if (clientSocket != null) clientSocket.close(); @@ -238,7 +238,13 @@ public class ProxyServer extends Thread implements Closeable { i++; commonInit(dest, 80); - serverOut.write(buf, i, buf.length-i); + OutputStream sout; + synchronized (this) { + if (closing) return; + sout = serverOut; + } + // might fail if we're closing but we don't care. + sout.write(buf, i, buf.length-i); proxyCommon(); } catch (URISyntaxException e) { @@ -246,7 +252,8 @@ public class ProxyServer extends Thread implements Closeable { } } - void commonInit(String dest, int defaultPort) throws IOException { + synchronized void commonInit(String dest, int defaultPort) throws IOException { + if (closing) return; int port; String[] hostport = dest.split(":"); if (hostport.length == 1) { @@ -261,7 +268,8 @@ public class ProxyServer extends Thread implements Closeable { serverIn = new BufferedInputStream(serverSocket.getInputStream()); } - void proxyCommon() throws IOException { + synchronized void proxyCommon() throws IOException { + if (closing) return; out = new Thread(() -> { try { byte[] bb = new byte[8000]; @@ -269,6 +277,7 @@ public class ProxyServer extends Thread implements Closeable { while ((n = clientIn.read(bb)) != -1) { serverOut.write(bb, 0, n); } + closing = true; serverSocket.close(); clientSocket.close(); } catch (IOException e) { @@ -284,6 +293,7 @@ public class ProxyServer extends Thread implements Closeable { while ((n = serverIn.read(bb)) != -1) { clientOut.write(bb, 0, n); } + closing = true; serverSocket.close(); clientSocket.close(); } catch (IOException e) { @@ -302,7 +312,9 @@ public class ProxyServer extends Thread implements Closeable { } void doTunnel(String dest) throws IOException { + if (closing) return; // no need to go further. commonInit(dest, 443); + // might fail if we're closing, but we don't care. clientOut.write("HTTP/1.1 200 OK\r\n\r\n".getBytes()); proxyCommon(); } diff --git a/test/jdk/java/net/httpclient/RetryWithCookie.java b/test/jdk/java/net/httpclient/RetryWithCookie.java index 5883cfcfc92..f5f06d7ad28 100644 --- a/test/jdk/java/net/httpclient/RetryWithCookie.java +++ b/test/jdk/java/net/httpclient/RetryWithCookie.java @@ -69,6 +69,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import static java.lang.System.out; +import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.nio.charset.StandardCharsets.UTF_8; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -106,6 +107,7 @@ public class RetryWithCookie implements HttpServerAdapters { out.printf("%n---- starting (%s) ----%n", uriString); CookieManager cookieManager = new CookieManager(); HttpClient client = HttpClient.newBuilder() + .proxy(NO_PROXY) .followRedirects(Redirect.ALWAYS) .cookieHandler(cookieManager) .sslContext(sslContext) diff --git a/test/jdk/java/net/httpclient/SmallTimeout.java b/test/jdk/java/net/httpclient/SmallTimeout.java index 17729f235ff..91ffb3305c6 100644 --- a/test/jdk/java/net/httpclient/SmallTimeout.java +++ b/test/jdk/java/net/httpclient/SmallTimeout.java @@ -85,12 +85,14 @@ public class SmallTimeout { ss.setReuseAddress(false); ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); int port = ss.getLocalPort(); - URI uri = new URI("http://localhost:" + port + "/"); + URI u = new URI("http://localhost:" + port + "/"); HttpRequest[] requests = new HttpRequest[TIMEOUTS.length]; out.println("--- TESTING Async"); for (int i = 0; i < TIMEOUTS.length; i++) { + final int n = i; + URI uri = new URI(u.toString() + "/r" + n); requests[i] = HttpRequest.newBuilder(uri) .timeout(Duration.ofMillis(TIMEOUTS[i])) .GET() @@ -102,24 +104,25 @@ public class SmallTimeout { .whenComplete((HttpResponse r, Throwable t) -> { Throwable cause = null; if (r != null) { - out.println("Unexpected response: " + r); - cause = new RuntimeException("Unexpected response"); + out.println("Unexpected response for r" + n + ": " + r); + cause = new RuntimeException("Unexpected response for r" + n); error = true; } if (t != null) { if (!(t.getCause() instanceof HttpTimeoutException)) { - out.println("Wrong exception type:" + t.toString()); + out.println("Wrong exception type for r" + n + ":" + t.toString()); Throwable c = t.getCause() == null ? t : t.getCause(); c.printStackTrace(); cause = c; error = true; } else { - out.println("Caught expected timeout: " + t.getCause()); + out.println("Caught expected timeout for r" + n +": " + t.getCause()); } } if (t == null && r == null) { - out.println("Both response and throwable are null!"); - cause = new RuntimeException("Both response and throwable are null!"); + out.println("Both response and throwable are null for r" + n + "!"); + cause = new RuntimeException("Both response and throwable are null for r" + + n + "!"); error = true; } queue.add(HttpResult.of(req,cause)); @@ -134,11 +137,14 @@ public class SmallTimeout { // Repeat blocking in separate threads. Use queue to wait. out.println("--- TESTING Sync"); + System.err.println("================= TESTING Sync ====================="); // For running blocking response tasks ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < TIMEOUTS.length; i++) { + final int n = i; + URI uri = new URI(u.toString()+"/sync/r" + n); requests[i] = HttpRequest.newBuilder(uri) .timeout(Duration.ofMillis(TIMEOUTS[i])) .GET() @@ -148,11 +154,13 @@ public class SmallTimeout { executor.execute(() -> { Throwable cause = null; try { - client.send(req, BodyHandlers.replacing(null)); + HttpResponse r = client.send(req, BodyHandlers.replacing(null)); + out.println("Unexpected success for r" + n +": " + r); } catch (HttpTimeoutException e) { - out.println("Caught expected timeout: " + e); + out.println("Caught expected timeout for r" + n +": " + e); } catch (Throwable ee) { Throwable c = ee.getCause() == null ? ee : ee.getCause(); + out.println("Unexpected exception for r" + n + ": " + c); c.printStackTrace(); cause = c; error = true; diff --git a/test/jdk/java/net/httpclient/TimeoutOrdering.java b/test/jdk/java/net/httpclient/TimeoutOrdering.java index 4a4cba2b984..a39242c871a 100644 --- a/test/jdk/java/net/httpclient/TimeoutOrdering.java +++ b/test/jdk/java/net/httpclient/TimeoutOrdering.java @@ -77,21 +77,22 @@ public class TimeoutOrdering { .build(); final HttpRequest req = requests[i]; + final int j = i; CompletableFuture> response = client .sendAsync(req, BodyHandlers.replacing(null)) .whenComplete((HttpResponse r, Throwable t) -> { if (r != null) { - out.println("Unexpected response: " + r); + out.println("Unexpected response for r" + j + ": " + r); error = true; } if (t != null) { if (!(t.getCause() instanceof HttpTimeoutException)) { - out.println("Wrong exception type:" + t.toString()); + out.println("Wrong exception type for r" + j + ": " + t.toString()); Throwable c = t.getCause() == null ? t : t.getCause(); c.printStackTrace(); error = true; } else { - out.println("Caught expected timeout: " + t.getCause()); + out.println("Caught expected timeout for r" + j + ": " + t.getCause()); } } queue.add(req); @@ -117,16 +118,21 @@ public class TimeoutOrdering { .build(); final HttpRequest req = requests[i]; + final int j = i; executor.execute(() -> { try { - client.send(req, BodyHandlers.replacing(null)); + HttpResponse r = client.send(req, BodyHandlers.replacing(null)); + out.println("Unexpected response for r" + j + ": " + r); + error = true; } catch (HttpTimeoutException e) { - out.println("Caught expected timeout: " + e); - queue.offer(req); + out.println("Caught expected timeout for r" + j +": " + e); } catch (IOException | InterruptedException ee) { Throwable c = ee.getCause() == null ? ee : ee.getCause(); + out.println("Wrong exception type for r" + j + ": " + c.toString()); c.printStackTrace(); error = true; + } finally { + queue.offer(req); } }); } diff --git a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/CircularBufferTest.java b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/CircularBufferTest.java index 20d06198d8d..307cbd77db9 100644 --- a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/CircularBufferTest.java +++ b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/CircularBufferTest.java @@ -25,13 +25,16 @@ package jdk.internal.net.http.hpack; import org.testng.annotations.Test; import jdk.internal.net.http.hpack.SimpleHeaderTable.CircularBuffer; +import java.util.Arrays; import java.util.Queue; import java.util.Random; import java.util.concurrent.ArrayBlockingQueue; +import static jdk.internal.net.http.common.Utils.pow2Size; import static org.testng.Assert.assertEquals; import static jdk.internal.net.http.hpack.TestHelper.assertVoidThrows; import static jdk.internal.net.http.hpack.TestHelper.newRandom; +import static org.testng.Assert.assertTrue; public final class CircularBufferTest { @@ -80,6 +83,8 @@ public final class CircularBufferTest { private void resizeOnce(int capacity) { + capacity = pow2Size(capacity); + int nextNumberToPut = 0; Queue referenceQueue = new ArrayBlockingQueue<>(capacity); @@ -104,11 +109,15 @@ public final class CircularBufferTest { Integer[] expected = referenceQueue.toArray(new Integer[0]); buffer.resize(expected.length); - assertEquals(buffer.elements, expected); + boolean equals = Arrays.equals(buffer.elements, 0, buffer.size, + expected, 0, expected.length); + assertTrue(equals); } private void queueOnce(int capacity, int numWraps) { + capacity = pow2Size(capacity); + Queue referenceQueue = new ArrayBlockingQueue<>(capacity); CircularBuffer buffer = new CircularBuffer<>(capacity); diff --git a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/DecoderTest.java b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/DecoderTest.java index cf302dab135..34eb5103bf8 100644 --- a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/DecoderTest.java +++ b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/DecoderTest.java @@ -623,8 +623,10 @@ public final class DecoderTest { testAllSplits(() -> new Decoder(256), hexdump, expectedHeaderTable, expectedHeaderList); } - private static void testAllSplits(Supplier supplier, String hexdump, - String expectedHeaderTable, String expectedHeaderList) { + private static void testAllSplits(Supplier supplier, + String hexdump, + String expectedHeaderTable, + String expectedHeaderList) { ByteBuffer source = SpecHelper.toBytes(hexdump); BuffersTestingKit.forEachSplit(source, iterable -> { @@ -651,6 +653,46 @@ public final class DecoderTest { assertEquals(d.getTable().getStateString(), expectedHeaderTable); assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); }); + + // Now introduce last ByteBuffer which is empty and EOF (mimics idiom + // I've found in HttpClient code) + BuffersTestingKit.forEachSplit(source, iterable -> { + List actual = new LinkedList<>(); + Iterator i = iterable.iterator(); + if (!i.hasNext()) { + return; + } + Decoder d = supplier.get(); + do { + ByteBuffer n = i.next(); + try { + d.decode(n, false, (name, value) -> { + if (value == null) { + actual.add(name.toString()); + } else { + actual.add(name + ": " + value); + } + }); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } while (i.hasNext()); + + try { + d.decode(ByteBuffer.allocate(0), false, (name, value) -> { + if (value == null) { + actual.add(name.toString()); + } else { + actual.add(name + ": " + value); + } + }); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + assertEquals(d.getTable().getStateString(), expectedHeaderTable); + assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); + }); } // diff --git a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HuffmanTest.java b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HuffmanTest.java index 2a0e5c6bc72..1699afe5116 100644 --- a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HuffmanTest.java +++ b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HuffmanTest.java @@ -328,7 +328,7 @@ public final class HuffmanTest { parseInt(hex, 16), parseInt(len)); StringBuilder actual = new StringBuilder(); - Huffman.Reader t = new Huffman.Reader(); + NaiveHuffman.Reader t = new NaiveHuffman.Reader(); t.read(ByteBuffer.wrap(bytes), actual, false, true); // What has been read MUST represent a single symbol @@ -338,6 +338,8 @@ public final class HuffmanTest { // characters (as some of them might not be visible) assertEquals(actual.charAt(0), expected); i++; + + // maybe not report EOS but rather throw an expected exception? } assertEquals(i, 257); // 256 + EOS } @@ -502,13 +504,19 @@ public final class HuffmanTest { "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); } + @Test + public void read_13() { + read("6274 a6b4 0989 4de4 b27f 80", + "/https2/fixed?0"); + } + @Test public void test_trie_has_no_empty_nodes() { - Huffman.Node root = Huffman.INSTANCE.getRoot(); - Stack backlog = new Stack<>(); + NaiveHuffman.Node root = NaiveHuffman.INSTANCE.getRoot(); + Stack backlog = new Stack<>(); backlog.push(root); while (!backlog.isEmpty()) { - Huffman.Node n = backlog.pop(); + NaiveHuffman.Node n = backlog.pop(); // The only type of nodes we couldn't possibly catch during // construction is an empty node: no children and no char if (n.left != null) { @@ -525,11 +533,11 @@ public final class HuffmanTest { @Test public void test_trie_has_257_nodes() { int count = 0; - Huffman.Node root = Huffman.INSTANCE.getRoot(); - Stack backlog = new Stack<>(); + NaiveHuffman.Node root = NaiveHuffman.INSTANCE.getRoot(); + Stack backlog = new Stack<>(); backlog.push(root); while (!backlog.isEmpty()) { - Huffman.Node n = backlog.pop(); + NaiveHuffman.Node n = backlog.pop(); if (n.left != null) { backlog.push(n.left); } @@ -546,7 +554,7 @@ public final class HuffmanTest { @Test public void cant_encode_outside_byte() { TestHelper.Block coding = - () -> new Huffman.Writer() + () -> new NaiveHuffman.Writer() .from(((char) 256) + "", 0, 1) .write(ByteBuffer.allocate(1)); RuntimeException e = @@ -558,7 +566,7 @@ public final class HuffmanTest { ByteBuffer source = SpecHelper.toBytes(hexdump); Appendable actual = new StringBuilder(); try { - new Huffman.Reader().read(source, actual, true); + new QuickHuffman.Reader().read(source, actual, true); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -566,9 +574,9 @@ public final class HuffmanTest { } private static void write(String decoded, String hexdump) { - int n = Huffman.INSTANCE.lengthOf(decoded); + Huffman.Writer writer = new QuickHuffman.Writer(); + int n = writer.lengthOf(decoded); ByteBuffer destination = ByteBuffer.allocate(n); // Extra margin (1) to test having more bytes in the destination than needed is ok - Huffman.Writer writer = new Huffman.Writer(); BuffersTestingKit.forEachSplit(destination, byteBuffers -> { writer.from(decoded, 0, decoded.length()); boolean written = false; diff --git a/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java b/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java index f96c6635c82..d6c30e41074 100644 --- a/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java +++ b/test/jdk/java/net/httpclient/http2/server/Http2TestServer.java @@ -67,11 +67,11 @@ public class Http2TestServer implements AutoCloseable { } public Http2TestServer(String serverName, boolean secure, int port) throws Exception { - this(serverName, secure, port, getDefaultExecutor(), null); + this(serverName, secure, port, getDefaultExecutor(), 50, null); } public Http2TestServer(boolean secure, int port) throws Exception { - this(null, secure, port, getDefaultExecutor(), null); + this(null, secure, port, getDefaultExecutor(), 50, null); } public InetSocketAddress getAddress() { @@ -85,19 +85,29 @@ public class Http2TestServer implements AutoCloseable { public Http2TestServer(boolean secure, SSLContext context) throws Exception { - this(null, secure, 0, null, context); + this(null, secure, 0, null, 50, context); } public Http2TestServer(String serverName, boolean secure, SSLContext context) throws Exception { - this(serverName, secure, 0, null, context); + this(serverName, secure, 0, null, 50, context); } public Http2TestServer(boolean secure, int port, ExecutorService exec, SSLContext context) throws Exception { - this(null, secure, port, exec, context); + this(null, secure, port, exec, 50, context); + } + + public Http2TestServer(String serverName, + boolean secure, + int port, + ExecutorService exec, + SSLContext context) + throws Exception + { + this(serverName, secure, port, exec, 50, context); } /** @@ -109,20 +119,22 @@ public class Http2TestServer implements AutoCloseable { * @param secure https or http * @param port listen port * @param exec executor service (cached thread pool is used if null) + * @param backlog the server socket backlog * @param context the SSLContext used when secure is true */ public Http2TestServer(String serverName, boolean secure, int port, ExecutorService exec, + int backlog, SSLContext context) throws Exception { this.serverName = serverName; if (secure) { - server = initSecure(port); + server = initSecure(port, backlog); } else { - server = initPlaintext(port); + server = initPlaintext(port, backlog); } this.secure = secure; this.exec = exec == null ? getDefaultExecutor() : exec; @@ -171,10 +183,10 @@ public class Http2TestServer implements AutoCloseable { return handler; } - final ServerSocket initPlaintext(int port) throws Exception { + final ServerSocket initPlaintext(int port, int backlog) throws Exception { ServerSocket ss = new ServerSocket(); ss.setReuseAddress(false); - ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog); return ss; } @@ -192,7 +204,7 @@ public class Http2TestServer implements AutoCloseable { } - final ServerSocket initSecure(int port) throws Exception { + final ServerSocket initSecure(int port, int backlog) throws Exception { ServerSocketFactory fac; if (sslContext != null) { fac = sslContext.getServerSocketFactory(); @@ -201,7 +213,7 @@ public class Http2TestServer implements AutoCloseable { } SSLServerSocket se = (SSLServerSocket) fac.createServerSocket(); se.setReuseAddress(false); - se.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + se.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog); SSLParameters sslp = se.getSSLParameters(); sslp.setApplicationProtocols(new String[]{"h2"}); sslp.setEndpointIdentificationAlgorithm("HTTPS"); diff --git a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java index 2b933c1a3f1..a08446a3224 100644 --- a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java +++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java @@ -200,6 +200,7 @@ public class DummyWebSocketServer implements Closeable { thread.start(); } catch (IOException e) { close(ssc); + throw e; } err.println("Started at: " + getURI()); } diff --git a/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java b/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java index d91002c9d86..8116e8dc722 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java @@ -37,8 +37,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingBinaryPingClose extends PendingOperations { @@ -51,7 +51,7 @@ public class PendingBinaryPingClose extends PendingOperations { repeatable(() -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); ByteBuffer data = ByteBuffer.allocate(65536); diff --git a/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java b/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java index 289eba86270..b810a47eaba 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java @@ -37,8 +37,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingBinaryPongClose extends PendingOperations { @@ -51,7 +51,7 @@ public class PendingBinaryPongClose extends PendingOperations { repeatable(() -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); ByteBuffer data = ByteBuffer.allocate(65536); diff --git a/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java b/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java index af1f9daea1d..99d5847a6bd 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java @@ -39,8 +39,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingPingBinaryClose extends PendingOperations { @@ -53,7 +53,7 @@ public class PendingPingBinaryClose extends PendingOperations { repeatable( () -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); ByteBuffer data = ByteBuffer.allocate(125); diff --git a/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java b/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java index 5cec4288c95..050f8098d2d 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java @@ -39,8 +39,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingPingTextClose extends PendingOperations { @@ -53,7 +53,7 @@ public class PendingPingTextClose extends PendingOperations { repeatable( () -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); ByteBuffer data = ByteBuffer.allocate(125); diff --git a/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java b/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java index f57b33cfa66..e715a83b7e9 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java @@ -39,8 +39,8 @@ import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingPongBinaryClose extends PendingOperations { @@ -53,7 +53,7 @@ public class PendingPongBinaryClose extends PendingOperations { repeatable( () -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); ByteBuffer data = ByteBuffer.allocate(125); diff --git a/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java b/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java index 50e4552a5e8..fddec8da4c1 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java @@ -40,6 +40,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; import static java.net.http.HttpClient.newHttpClient; public class PendingPongTextClose extends PendingOperations { @@ -53,7 +55,7 @@ public class PendingPongTextClose extends PendingOperations { repeatable( () -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); ByteBuffer data = ByteBuffer.allocate(125); diff --git a/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java b/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java index 439ad31f169..c5fc62e018a 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java @@ -38,8 +38,8 @@ import java.nio.CharBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingTextPingClose extends PendingOperations { @@ -52,7 +52,7 @@ public class PendingTextPingClose extends PendingOperations { repeatable(() -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); CharBuffer data = CharBuffer.allocate(65536); diff --git a/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java b/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java index 6d13d81dfb2..e688d42125e 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java @@ -38,8 +38,8 @@ import java.nio.CharBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; public class PendingTextPongClose extends PendingOperations { @@ -52,7 +52,7 @@ public class PendingTextPongClose extends PendingOperations { repeatable(() -> { server = Support.notReadingServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); CharBuffer data = CharBuffer.allocate(65536); diff --git a/test/jdk/java/net/httpclient/websocket/SendTest.java b/test/jdk/java/net/httpclient/websocket/SendTest.java index f1bce0769e1..a152743af7f 100644 --- a/test/jdk/java/net/httpclient/websocket/SendTest.java +++ b/test/jdk/java/net/httpclient/websocket/SendTest.java @@ -35,7 +35,8 @@ import org.testng.annotations.Test; import java.io.IOException; import java.net.http.WebSocket; -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; @@ -58,7 +59,7 @@ public class SendTest { public void sendMethodsThrowNPE() throws IOException { server = new DummyWebSocketServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -89,7 +90,7 @@ public class SendTest { public void sendCloseCompleted() throws IOException { server = new DummyWebSocketServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); webSocket.sendClose(NORMAL_CLOSURE, "").join(); diff --git a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java index b27906f64a0..2feac502b93 100644 --- a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java +++ b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java @@ -51,6 +51,8 @@ import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; + +import static java.net.http.HttpClient.Builder.NO_PROXY; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.fail; @@ -79,6 +81,7 @@ public class WSHandshakeExceptionTest { HttpClient newHttpClient() { return HttpClient.newBuilder() + .proxy(NO_PROXY) .executor(executor) .sslContext(sslContext) .build(); diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java index f297771f419..e739c5ef795 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java @@ -43,8 +43,8 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Random; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -71,7 +71,7 @@ public class WebSocketExtendedTest { public void binary(ByteBuffer expected) throws IOException, InterruptedException { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); - WebSocket ws = newHttpClient() + WebSocket ws = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -166,7 +166,7 @@ public class WebSocketExtendedTest { public void ping(ByteBuffer expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); - WebSocket ws = newHttpClient() + WebSocket ws = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -188,7 +188,7 @@ public class WebSocketExtendedTest { public void pong(ByteBuffer expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); - WebSocket ws = newHttpClient() + WebSocket ws = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -210,7 +210,7 @@ public class WebSocketExtendedTest { public void close(int statusCode, String reason) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); - WebSocket ws = newHttpClient() + WebSocket ws = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -233,7 +233,7 @@ public class WebSocketExtendedTest { public void text(String expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); - WebSocket ws = newHttpClient() + WebSocket ws = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java index 0821ac575e3..e953e2b840b 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java @@ -42,8 +42,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - -import static java.net.http.HttpClient.newHttpClient; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; @@ -73,7 +73,7 @@ public class WebSocketTest { public void illegalArgument() throws IOException { server = new DummyWebSocketServer(); server.open(); - webSocket = newHttpClient() + webSocket = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -137,7 +137,7 @@ public class WebSocketTest { public void partialBinaryThenText() throws IOException { server = new DummyWebSocketServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); webSocket.sendBinary(ByteBuffer.allocate(16), false).join(); @@ -152,7 +152,7 @@ public class WebSocketTest { public void partialTextThenBinary() throws IOException { server = new DummyWebSocketServer(); server.open(); - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -168,7 +168,7 @@ public class WebSocketTest { public void sendMethodsThrowIOE1() throws IOException { server = new DummyWebSocketServer(); server.open(); - webSocket = newHttpClient() + webSocket = newBuilder().proxy(NO_PROXY).build() .newWebSocketBuilder() .buildAsync(server.getURI(), new WebSocket.Listener() { }) .join(); @@ -221,7 +221,7 @@ public class WebSocketTest { } }; - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), listener) .join(); @@ -333,7 +333,7 @@ public class WebSocketTest { } }; - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), listener) .join(); @@ -407,7 +407,7 @@ public class WebSocketTest { } }; - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), listener) .join(); @@ -500,7 +500,7 @@ public class WebSocketTest { } }; - webSocket = newHttpClient().newWebSocketBuilder() + webSocket = newBuilder().proxy(NO_PROXY).build().newWebSocketBuilder() .buildAsync(server.getURI(), listener) .join(); From 7f7d103c8580ac6613814676ab46087d111bc005 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Wed, 2 May 2018 13:44:46 +0200 Subject: [PATCH 100/102] 8191471: Elastic TLABs for G1 Reviewed-by: tschatzl, pliden --- src/hotspot/share/gc/g1/g1AllocRegion.cpp | 120 +++++++++++++++--- src/hotspot/share/gc/g1/g1AllocRegion.hpp | 68 ++++++++-- .../share/gc/g1/g1AllocRegion.inline.hpp | 17 +++ src/hotspot/share/gc/g1/g1Allocator.cpp | 9 +- src/hotspot/share/gc/g1/g1Allocator.hpp | 4 +- .../share/gc/g1/g1Allocator.inline.hpp | 10 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 33 +++-- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 8 +- .../gc/parallel/parallelScavengeHeap.cpp | 9 +- .../gc/parallel/parallelScavengeHeap.hpp | 2 +- src/hotspot/share/gc/shared/collectedHeap.cpp | 23 +++- src/hotspot/share/gc/shared/collectedHeap.hpp | 8 +- .../share/gc/shared/genCollectedHeap.cpp | 15 ++- .../share/gc/shared/genCollectedHeap.hpp | 4 +- .../gc/shared/threadLocalAllocBuffer.hpp | 3 + .../shared/threadLocalAllocBuffer.inline.hpp | 12 +- 16 files changed, 268 insertions(+), 77 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index 56c9aae5362..73a5bdb6a11 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -95,33 +95,40 @@ size_t G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region) { return result; } +size_t G1AllocRegion::retire_internal(HeapRegion* alloc_region, bool fill_up) { + // We never have to check whether the active region is empty or not, + // and potentially free it if it is, given that it's guaranteed that + // it will never be empty. + size_t waste = 0; + assert_alloc_region(!alloc_region->is_empty(), + "the alloc region should never be empty"); + + if (fill_up) { + waste = fill_up_remaining_space(alloc_region); + } + + assert_alloc_region(alloc_region->used() >= _used_bytes_before, "invariant"); + size_t allocated_bytes = alloc_region->used() - _used_bytes_before; + retire_region(alloc_region, allocated_bytes); + _used_bytes_before = 0; + + return waste; +} + size_t G1AllocRegion::retire(bool fill_up) { assert_alloc_region(_alloc_region != NULL, "not initialized properly"); - size_t result = 0; + size_t waste = 0; trace("retiring"); HeapRegion* alloc_region = _alloc_region; if (alloc_region != _dummy_region) { - // We never have to check whether the active region is empty or not, - // and potentially free it if it is, given that it's guaranteed that - // it will never be empty. - assert_alloc_region(!alloc_region->is_empty(), - "the alloc region should never be empty"); - - if (fill_up) { - result = fill_up_remaining_space(alloc_region); - } - - assert_alloc_region(alloc_region->used() >= _used_bytes_before, "invariant"); - size_t allocated_bytes = alloc_region->used() - _used_bytes_before; - retire_region(alloc_region, allocated_bytes); - _used_bytes_before = 0; - _alloc_region = _dummy_region; + waste = retire_internal(alloc_region, fill_up); + reset_alloc_region(); } trace("retired"); - return result; + return waste; } HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, @@ -245,7 +252,8 @@ void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_ G1AllocRegion::G1AllocRegion(const char* name, bool bot_updates) : _name(name), _bot_updates(bot_updates), - _alloc_region(NULL), _count(0), _used_bytes_before(0) { } + _alloc_region(NULL), _count(0), + _used_bytes_before(0) { } HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size, @@ -258,6 +266,82 @@ void MutatorAllocRegion::retire_region(HeapRegion* alloc_region, _g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes); } +void MutatorAllocRegion::init() { + assert(_retained_alloc_region == NULL, "Pre-condition"); + G1AllocRegion::init(); + _wasted_bytes = 0; +} + +bool MutatorAllocRegion::should_retain(HeapRegion* region) { + size_t free_bytes = region->free(); + if (free_bytes < MinTLABSize) { + return false; + } + + if (_retained_alloc_region != NULL && + free_bytes < _retained_alloc_region->free()) { + return false; + } + + return true; +} + +size_t MutatorAllocRegion::retire(bool fill_up) { + size_t waste = 0; + trace("retiring"); + HeapRegion* current_region = get(); + if (current_region != NULL) { + // Retain the current region if it fits a TLAB and has more + // free than the currently retained region. + if (should_retain(current_region)) { + trace("mutator retained"); + if (_retained_alloc_region != NULL) { + waste = retire_internal(_retained_alloc_region, true); + } + _retained_alloc_region = current_region; + } else { + waste = retire_internal(current_region, fill_up); + } + reset_alloc_region(); + } + + _wasted_bytes += waste; + trace("retired"); + return waste; +} + +size_t MutatorAllocRegion::used_in_alloc_regions() { + size_t used = 0; + HeapRegion* hr = get(); + if (hr != NULL) { + used += hr->used(); + } + + hr = _retained_alloc_region; + if (hr != NULL) { + used += hr->used(); + } + return used; +} + +HeapRegion* MutatorAllocRegion::release() { + HeapRegion* ret = G1AllocRegion::release(); + + // The retained alloc region must be retired and this must be + // done after the above call to release the mutator alloc region, + // since it might update the _retained_alloc_region member. + if (_retained_alloc_region != NULL) { + _wasted_bytes += retire_internal(_retained_alloc_region, false); + _retained_alloc_region = NULL; + } + log_debug(gc, alloc, region)("Mutator Allocation stats, regions: %u, wasted size: " SIZE_FORMAT "%s (%4.1f%%)", + count(), + byte_size_in_proper_unit(_wasted_bytes), + proper_unit_for_byte_size(_wasted_bytes), + percent_of(_wasted_bytes, count() * HeapRegion::GrainBytes)); + return ret; +} + HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size, bool force) { assert(!force, "not supported for GC alloc regions"); diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index 51c3acd2da5..593612975f8 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -80,6 +80,20 @@ private: // whether the _alloc_region is NULL or not. static HeapRegion* _dummy_region; + // After a region is allocated by alloc_new_region, this + // method is used to set it as the active alloc_region + void update_alloc_region(HeapRegion* alloc_region); + + // Allocate a new active region and use it to perform a word_size + // allocation. The force parameter will be passed on to + // G1CollectedHeap::allocate_new_alloc_region() and tells it to try + // to allocate a new region even if the max has been reached. + HeapWord* new_alloc_region_and_allocate(size_t word_size, bool force); + +protected: + // Reset the alloc region to point a the dummy region. + void reset_alloc_region(); + // Perform a non-MT-safe allocation out of the given region. inline HeapWord* allocate(HeapRegion* alloc_region, size_t word_size); @@ -102,23 +116,14 @@ private: // the space. size_t fill_up_remaining_space(HeapRegion* alloc_region); - // After a region is allocated by alloc_new_region, this - // method is used to set it as the active alloc_region - void update_alloc_region(HeapRegion* alloc_region); - - // Allocate a new active region and use it to perform a word_size - // allocation. The force parameter will be passed on to - // G1CollectedHeap::allocate_new_alloc_region() and tells it to try - // to allocate a new region even if the max has been reached. - HeapWord* new_alloc_region_and_allocate(size_t word_size, bool force); - -protected: // Retire the active allocating region. If fill_up is true then make // sure that the region is full before we retire it so that no one // else can allocate out of it. // Returns the number of bytes that have been filled up during retire. virtual size_t retire(bool fill_up); + size_t retire_internal(HeapRegion* alloc_region, bool fill_up); + // For convenience as subclasses use it. static G1CollectedHeap* _g1h; @@ -177,7 +182,7 @@ public: inline HeapWord* attempt_allocation_force(size_t word_size); // Should be called before we start using this object. - void init(); + virtual void init(); // This can be used to set the active region to a specific // region. (Use Example: we try to retain the last old GC alloc @@ -197,14 +202,49 @@ public: }; class MutatorAllocRegion : public G1AllocRegion { +private: + // Keeps track of the total waste generated during the current + // mutator phase. + size_t _wasted_bytes; + + // Retained allocation region. Used to lower the waste generated + // during mutation by having two active regions if the free space + // in a region about to be retired still could fit a TLAB. + HeapRegion* volatile _retained_alloc_region; + + // Decide if the region should be retained, based on the free size + // in it and the free size in the currently retained region, if any. + bool should_retain(HeapRegion* region); protected: virtual HeapRegion* allocate_new_region(size_t word_size, bool force); virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes); + virtual size_t retire(bool fill_up); public: MutatorAllocRegion() - : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */) { } -}; + : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */), + _wasted_bytes(0), + _retained_alloc_region(NULL) { } + // Returns the combined used memory in the current alloc region and + // the retained alloc region. + size_t used_in_alloc_regions(); + + // Perform an allocation out of the retained allocation region, with the given + // minimum and desired size. Returns the actual size allocated (between + // minimum and desired size) in actual_word_size if the allocation has been + // successful. + // Should be called without holding a lock. It will try to allocate lock-free + // out of the retained region, or return NULL if it was unable to. + inline HeapWord* attempt_retained_allocation(size_t min_word_size, + size_t desired_word_size, + size_t* actual_word_size); + + // This specialization of release() makes sure that the retained alloc + // region is retired and set to NULL. + virtual HeapRegion* release(); + + virtual void init(); +}; // Common base class for allocation regions used during GC. class G1GCAllocRegion : public G1AllocRegion { protected: diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp index 1c08b8e2896..fdf7712dfbe 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp @@ -36,6 +36,10 @@ } while (0) +inline void G1AllocRegion::reset_alloc_region() { + _alloc_region = _dummy_region; +} + inline HeapWord* G1AllocRegion::allocate(HeapRegion* alloc_region, size_t word_size) { assert(alloc_region != NULL, "pre-condition"); @@ -126,4 +130,17 @@ inline HeapWord* G1AllocRegion::attempt_allocation_force(size_t word_size) { return NULL; } +inline HeapWord* MutatorAllocRegion::attempt_retained_allocation(size_t min_word_size, + size_t desired_word_size, + size_t* actual_word_size) { + if (_retained_alloc_region != NULL) { + HeapWord* result = par_allocate(_retained_alloc_region, min_word_size, desired_word_size, actual_word_size); + if (result != NULL) { + trace("alloc retained", min_word_size, desired_word_size, *actual_word_size, result); + return result; + } + } + return NULL; +} + #endif // SHARE_VM_GC_G1_G1ALLOCREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 7c31abc5798..15f20808ea9 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -157,14 +157,7 @@ size_t G1Allocator::unsafe_max_tlab_alloc() { size_t G1Allocator::used_in_alloc_regions() { assert(Heap_lock->owner() != NULL, "Should be owned on this thread's behalf."); - size_t result = 0; - - // Read only once in case it is set to NULL concurrently - HeapRegion* hr = mutator_alloc_region()->get(); - if (hr != NULL) { - result += hr->used(); - } - return result; + return mutator_alloc_region()->used_in_alloc_regions(); } diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index 48c0e553773..f3ab401abfd 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -99,7 +99,9 @@ public: // Allocate blocks of memory during mutator time. - inline HeapWord* attempt_allocation(size_t word_size); + inline HeapWord* attempt_allocation(size_t min_word_size, + size_t desired_word_size, + size_t* actual_word_size); inline HeapWord* attempt_allocation_locked(size_t word_size); inline HeapWord* attempt_allocation_force(size_t word_size); diff --git a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp index edec0a4584f..cc24bc01281 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp @@ -41,8 +41,14 @@ inline OldGCAllocRegion* G1Allocator::old_gc_alloc_region() { return &_old_gc_alloc_region; } -inline HeapWord* G1Allocator::attempt_allocation(size_t word_size) { - return mutator_alloc_region()->attempt_allocation(word_size); +inline HeapWord* G1Allocator::attempt_allocation(size_t min_word_size, + size_t desired_word_size, + size_t* actual_word_size) { + HeapWord* result = mutator_alloc_region()->attempt_retained_allocation(min_word_size, desired_word_size, actual_word_size); + if (result != NULL) { + return result; + } + return mutator_alloc_region()->attempt_allocation(min_word_size, desired_word_size, actual_word_size); } inline HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index ed1b378ee83..4cc5b1b4720 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -384,11 +384,13 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) { return result; } -HeapWord* G1CollectedHeap::allocate_new_tlab(size_t word_size) { +HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size) { assert_heap_not_locked_and_not_at_safepoint(); - assert(!is_humongous(word_size), "we do not allow humongous TLABs"); + assert(!is_humongous(requested_size), "we do not allow humongous TLABs"); - return attempt_allocation(word_size); + return attempt_allocation(min_size, requested_size, actual_size); } HeapWord* @@ -399,7 +401,8 @@ G1CollectedHeap::mem_allocate(size_t word_size, if (is_humongous(word_size)) { return attempt_allocation_humongous(word_size); } - return attempt_allocation(word_size); + size_t dummy = 0; + return attempt_allocation(word_size, word_size, &dummy); } HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) { @@ -492,8 +495,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) { // first attempt (without holding the Heap_lock) here and the // follow-on attempt will be at the start of the next loop // iteration (after taking the Heap_lock). - - result = _allocator->attempt_allocation(word_size); + size_t dummy = 0; + result = _allocator->attempt_allocation(word_size, word_size, &dummy); if (result != NULL) { return result; } @@ -722,20 +725,28 @@ void G1CollectedHeap::fill_archive_regions(MemRegion* ranges, size_t count) { } } -inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size) { +inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size, + size_t desired_word_size, + size_t* actual_word_size) { assert_heap_not_locked_and_not_at_safepoint(); - assert(!is_humongous(word_size), "attempt_allocation() should not " + assert(!is_humongous(desired_word_size), "attempt_allocation() should not " "be called for humongous allocation requests"); - HeapWord* result = _allocator->attempt_allocation(word_size); + HeapWord* result = _allocator->attempt_allocation(min_word_size, desired_word_size, actual_word_size); if (result == NULL) { - result = attempt_allocation_slow(word_size); + *actual_word_size = desired_word_size; + result = attempt_allocation_slow(desired_word_size); } + assert_heap_not_locked(); if (result != NULL) { - dirty_young_block(result, word_size); + assert(*actual_word_size != 0, "Actual size must have been set here"); + dirty_young_block(result, *actual_word_size); + } else { + *actual_word_size = 0; } + return result; } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index cd4745a2746..cfbe3418a6b 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -420,7 +420,9 @@ private: // humongous allocation requests should go to mem_allocate() which // will satisfy them with a special path. - virtual HeapWord* allocate_new_tlab(size_t word_size); + virtual HeapWord* allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size); virtual HeapWord* mem_allocate(size_t word_size, bool* gc_overhead_limit_was_exceeded); @@ -428,7 +430,9 @@ private: // First-level mutator allocation attempt: try to allocate out of // the mutator alloc region without taking the Heap_lock. This // should only be used for non-humongous allocations. - inline HeapWord* attempt_allocation(size_t word_size); + inline HeapWord* attempt_allocation(size_t min_word_size, + size_t desired_word_size, + size_t* actual_word_size); // Second-level mutator allocation attempt: take the Heap_lock and // retry the allocation attempt, potentially scheduling a GC diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 03684211409..1cef9f63fde 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -478,8 +478,13 @@ size_t ParallelScavengeHeap::unsafe_max_tlab_alloc(Thread* thr) const { return young_gen()->eden_space()->unsafe_max_tlab_alloc(thr); } -HeapWord* ParallelScavengeHeap::allocate_new_tlab(size_t size) { - return young_gen()->allocate(size); +HeapWord* ParallelScavengeHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) { + HeapWord* result = young_gen()->allocate(requested_size); + if (result != NULL) { + *actual_size = requested_size; + } + + return result; } void ParallelScavengeHeap::accumulate_statistics_all_tlabs() { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index ff3c9fbc1b0..5d18efb92ac 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -85,7 +85,7 @@ class ParallelScavengeHeap : public CollectedHeap { protected: static inline size_t total_invocations(); - HeapWord* allocate_new_tlab(size_t size); + HeapWord* allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size); inline bool should_alloc_in_eden(size_t size) const; inline void death_march_check(HeapWord* const result, size_t size); diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index f4641a2cfcc..9387f39a240 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -384,17 +384,24 @@ HeapWord* CollectedHeap::allocate_from_tlab_slow(Klass* klass, Thread* thread, s return NULL; } - // Allocate a new TLAB... - HeapWord* obj = Universe::heap()->allocate_new_tlab(new_tlab_size); + // Allocate a new TLAB requesting new_tlab_size. Any size + // between minimal and new_tlab_size is accepted. + size_t actual_tlab_size = 0; + size_t min_tlab_size = ThreadLocalAllocBuffer::compute_min_size(size); + HeapWord* obj = Universe::heap()->allocate_new_tlab(min_tlab_size, new_tlab_size, &actual_tlab_size); if (obj == NULL) { + assert(actual_tlab_size == 0, "Allocation failed, but actual size was updated. min: " SIZE_FORMAT ", desired: " SIZE_FORMAT ", actual: " SIZE_FORMAT, + min_tlab_size, new_tlab_size, actual_tlab_size); return NULL; } + assert(actual_tlab_size != 0, "Allocation succeeded but actual size not updated. obj at: " PTR_FORMAT " min: " SIZE_FORMAT ", desired: " SIZE_FORMAT, + p2i(obj), min_tlab_size, new_tlab_size); - AllocTracer::send_allocation_in_new_tlab(klass, obj, new_tlab_size * HeapWordSize, size * HeapWordSize, thread); + AllocTracer::send_allocation_in_new_tlab(klass, obj, actual_tlab_size * HeapWordSize, size * HeapWordSize, thread); if (ZeroTLAB) { // ..and clear it. - Copy::zero_to_words(obj, new_tlab_size); + Copy::zero_to_words(obj, actual_tlab_size); } else { // ...and zap just allocated object. #ifdef ASSERT @@ -402,10 +409,10 @@ HeapWord* CollectedHeap::allocate_from_tlab_slow(Klass* klass, Thread* thread, s // ensure that the returned space is not considered parsable by // any concurrent GC thread. size_t hdr_size = oopDesc::header_size(); - Copy::fill_to_words(obj + hdr_size, new_tlab_size - hdr_size, badHeapWordVal); + Copy::fill_to_words(obj + hdr_size, actual_tlab_size - hdr_size, badHeapWordVal); #endif // ASSERT } - thread->tlab().fill(obj, obj + size, new_tlab_size); + thread->tlab().fill(obj, obj + size, actual_tlab_size); return obj; } @@ -506,7 +513,9 @@ void CollectedHeap::fill_with_objects(HeapWord* start, size_t words, bool zap) fill_with_object_impl(start, words, zap); } -HeapWord* CollectedHeap::allocate_new_tlab(size_t size) { +HeapWord* CollectedHeap::allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size) { guarantee(false, "thread-local allocation buffers not supported"); return NULL; } diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 3b479e96cf9..024656e0287 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -126,7 +126,13 @@ class CollectedHeap : public CHeapObj { CollectedHeap(); // Create a new tlab. All TLAB allocations must go through this. - virtual HeapWord* allocate_new_tlab(size_t size); + // To allow more flexible TLAB allocations min_size specifies + // the minimum size needed, while requested_size is the requested + // size based on ergonomics. The actually allocated size will be + // returned in actual_size. + virtual HeapWord* allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size); // Accumulate statistics on all tlabs. virtual void accumulate_statistics_all_tlabs(); diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index b14db143052..3a9dfa85c0b 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -1146,11 +1146,18 @@ size_t GenCollectedHeap::unsafe_max_tlab_alloc(Thread* thr) const { return 0; } -HeapWord* GenCollectedHeap::allocate_new_tlab(size_t size) { +HeapWord* GenCollectedHeap::allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size) { bool gc_overhead_limit_was_exceeded; - return mem_allocate_work(size /* size */, - true /* is_tlab */, - &gc_overhead_limit_was_exceeded); + HeapWord* result = mem_allocate_work(requested_size /* size */, + true /* is_tlab */, + &gc_overhead_limit_was_exceeded); + if (result != NULL) { + *actual_size = requested_size; + } + + return result; } // Requires "*prev_ptr" to be non-NULL. Deletes and a block of minimal size diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp index d675e4db936..4acde611770 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp @@ -297,7 +297,9 @@ public: virtual size_t tlab_capacity(Thread* thr) const; virtual size_t tlab_used(Thread* thr) const; virtual size_t unsafe_max_tlab_alloc(Thread* thr) const; - virtual HeapWord* allocate_new_tlab(size_t size); + virtual HeapWord* allocate_new_tlab(size_t min_size, + size_t requested_size, + size_t* actual_size); // The "requestor" generation is performing some garbage collection // action for which it would be useful to have scratch space. The diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index 483958fe632..074ac12e400 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -141,6 +141,9 @@ public: // Otherwise return 0; inline size_t compute_size(size_t obj_size); + // Compute the minimal needed tlab size for the given object size. + static inline size_t compute_min_size(size_t obj_size); + // Record slow allocation inline void record_slow_allocation(size_t obj_size); diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp index 9026887f66d..bb876a7d864 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp @@ -54,18 +54,15 @@ inline HeapWord* ThreadLocalAllocBuffer::allocate(size_t size) { } inline size_t ThreadLocalAllocBuffer::compute_size(size_t obj_size) { - const size_t aligned_obj_size = align_object_size(obj_size); - // Compute the size for the new TLAB. // The "last" tlab may be smaller to reduce fragmentation. // unsafe_max_tlab_alloc is just a hint. const size_t available_size = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize; - size_t new_tlab_size = MIN3(available_size, desired_size() + aligned_obj_size, max_size()); + size_t new_tlab_size = MIN3(available_size, desired_size() + align_object_size(obj_size), max_size()); // Make sure there's enough room for object and filler int[]. - const size_t obj_plus_filler_size = aligned_obj_size + alignment_reserve(); - if (new_tlab_size < obj_plus_filler_size) { + if (new_tlab_size < compute_min_size(obj_size)) { // If there isn't enough room for the allocation, return failure. log_trace(gc, tlab)("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ") returns failure", obj_size); @@ -76,6 +73,11 @@ inline size_t ThreadLocalAllocBuffer::compute_size(size_t obj_size) { return new_tlab_size; } +inline size_t ThreadLocalAllocBuffer::compute_min_size(size_t obj_size) { + const size_t aligned_obj_size = align_object_size(obj_size); + const size_t size_with_reserve = aligned_obj_size + alignment_reserve(); + return MAX2(size_with_reserve, MinTLABSize); +} void ThreadLocalAllocBuffer::record_slow_allocation(size_t obj_size) { // Raise size required to bypass TLAB next time. Why? Else there's From 45aa655cd028f056294ac0df0416789e0e8e0374 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Wed, 2 May 2018 13:44:49 +0200 Subject: [PATCH 101/102] 8202140: TLAB logging is not correct for G1 Reviewed-by: tschatzl, sangheki --- .../share/gc/shared/threadLocalAllocBuffer.cpp | 17 +++++++++-------- .../share/gc/shared/threadLocalAllocBuffer.hpp | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index 43b08bc5767..55ccfc1b008 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -89,7 +89,7 @@ void ThreadLocalAllocBuffer::accumulate_statistics() { } global_stats()->update_allocating_threads(); global_stats()->update_number_of_refills(_number_of_refills); - global_stats()->update_allocation(_number_of_refills * desired_size()); + global_stats()->update_allocation(_allocated_size); global_stats()->update_gc_waste(_gc_waste); global_stats()->update_slow_refill_waste(_slow_refill_waste); global_stats()->update_fast_refill_waste(_fast_refill_waste); @@ -157,17 +157,19 @@ void ThreadLocalAllocBuffer::resize() { } void ThreadLocalAllocBuffer::initialize_statistics() { - _number_of_refills = 0; - _fast_refill_waste = 0; - _slow_refill_waste = 0; - _gc_waste = 0; - _slow_allocations = 0; + _number_of_refills = 0; + _fast_refill_waste = 0; + _slow_refill_waste = 0; + _gc_waste = 0; + _slow_allocations = 0; + _allocated_size = 0; } void ThreadLocalAllocBuffer::fill(HeapWord* start, HeapWord* top, size_t new_size) { _number_of_refills++; + _allocated_size += new_size; print_stats("fill"); assert(top <= start + new_size - alignment_reserve(), "size too small"); initialize(start, top, start + new_size - alignment_reserve()); @@ -274,8 +276,7 @@ void ThreadLocalAllocBuffer::print_stats(const char* tag) { Thread* thrd = myThread(); size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste; - size_t alloc = _number_of_refills * _desired_size; - double waste_percent = percent_of(waste, alloc); + double waste_percent = percent_of(waste, _allocated_size); size_t tlab_used = Universe::heap()->tlab_used(thrd); log.trace("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" " desired_size: " SIZE_FORMAT "KB" diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index 074ac12e400..4d91a8aeb5c 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -58,6 +58,7 @@ private: unsigned _slow_refill_waste; unsigned _gc_waste; unsigned _slow_allocations; + size_t _allocated_size; AdaptiveWeightedAverage _allocation_fraction; // fraction of eden allocated in tlabs From 7dc011cccac59eeb91a49aec58886641988f225a Mon Sep 17 00:00:00 2001 From: Bernard Blaser Date: Wed, 2 May 2018 15:29:55 +0100 Subject: [PATCH 102/102] 8202372: Diagnostic with incorrect line info generated when compiling lambda expression Add tree position to speculative lambda tree Reviewed-by: vromero, jlahoda --- .../sun/tools/javac/comp/DeferredAttr.java | 2 +- .../tools/javac/lambda/8202372/T8202372.java | 45 +++++++++++++++++++ .../tools/javac/lambda/8202372/T8202372.out | 8 ++++ test/langtools/tools/javac/lvti/T8200199.java | 2 +- .../badTypeReference/BadTypeReference.java | 2 +- .../javac/preview/classReaderTest/Client.java | 2 +- 6 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 test/langtools/tools/javac/lambda/8202372/T8202372.java create mode 100644 test/langtools/tools/javac/lambda/8202372/T8202372.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java index c3a3964d1d8..1b74e1f7f11 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java @@ -441,7 +441,7 @@ public class DeferredAttr extends JCTree.Visitor { } else { stats.add((JCBlock)that.body); } - JCBlock lambdaBlock = make.Block(0, stats.toList()); + JCBlock lambdaBlock = make.at(that.pos).Block(0, stats.toList()); Env localEnv = attr.lambdaEnv(that, env); try { localEnv.info.returnResult = resultInfo; diff --git a/test/langtools/tools/javac/lambda/8202372/T8202372.java b/test/langtools/tools/javac/lambda/8202372/T8202372.java new file mode 100644 index 00000000000..18d971a4d61 --- /dev/null +++ b/test/langtools/tools/javac/lambda/8202372/T8202372.java @@ -0,0 +1,45 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8202372 + * @summary Diagnostic with incorrect line info generated when compiling lambda expression + * @compile/fail/ref=T8202372.out -XDrawDiagnostics T8202372.java + */ +class T8202372 { + + interface NonVoidFunc { + String m(); + } + + interface VoidFunc { + void m(); + } + + interface ParamFunc { + void m(String s); + } + + public void addVoid(VoidFunc v) {} + public void addNonVoid(NonVoidFunc nv) {} + public void addParam(ParamFunc p) {} + + void testVoid(T8202372 test) { + test.addVoid(() -> ""); + test.addVoid(() -> { return ""; }); + test.addVoid(() -> { }); + test.addVoid(() -> { return; }); + } + + void testNonVoid(T8202372 test) { + test.addNonVoid(() -> ""); + test.addNonVoid(() -> { return ""; }); + test.addNonVoid(() -> { }); + test.addNonVoid(() -> { return; }); + } + + void testParam(T8202372 test) { + test.addParam(() -> {}); + test.addParam((String x) -> { }); + test.addParam((String x1, String x2) -> { }); + test.addParam((int x) -> { }); + } +} \ No newline at end of file diff --git a/test/langtools/tools/javac/lambda/8202372/T8202372.out b/test/langtools/tools/javac/lambda/8202372/T8202372.out new file mode 100644 index 00000000000..368fe8bd808 --- /dev/null +++ b/test/langtools/tools/javac/lambda/8202372/T8202372.out @@ -0,0 +1,8 @@ +T8202372.java:26:13: compiler.err.cant.apply.symbol: kindname.method, addVoid, T8202372.VoidFunc, @22, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.stat.expr.expected)) +T8202372.java:27:13: compiler.err.cant.apply.symbol: kindname.method, addVoid, T8202372.VoidFunc, @22, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val))) +T8202372.java:35:13: compiler.err.cant.apply.symbol: kindname.method, addNonVoid, T8202372.NonVoidFunc, @25, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.String))) +T8202372.java:36:13: compiler.err.cant.apply.symbol: kindname.method, addNonVoid, T8202372.NonVoidFunc, @25, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val))) +T8202372.java:40:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) +T8202372.java:42:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) +T8202372.java:43:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) +7 errors diff --git a/test/langtools/tools/javac/lvti/T8200199.java b/test/langtools/tools/javac/lvti/T8200199.java index 60bcdfea20f..259ef81fa15 100644 --- a/test/langtools/tools/javac/lvti/T8200199.java +++ b/test/langtools/tools/javac/lvti/T8200199.java @@ -24,7 +24,7 @@ */ /* - * @test /nodynamioccopyright/ + * @test /nodynamiccopyright/ * @bug 8200199 * @summary javac suggests to use var even when var is used * @compile/fail/ref=T8200199.out -Werror -XDfind=local -XDrawDiagnostics T8200199.java diff --git a/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java b/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java index 0dfe7b6f08b..8bfe7c37725 100644 --- a/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java +++ b/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java @@ -24,7 +24,7 @@ */ /* - * @test /nodynamioccopyright/ + * @test /nodynamiccopyright/ * @bug 8177466 * @summary Add compiler support for local variable type-inference * @compile -source 8 pkg/var.java diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.java b/test/langtools/tools/javac/preview/classReaderTest/Client.java index 91ac53e334e..cf9d6e22f16 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.java +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.java @@ -1,5 +1,5 @@ /* - * @test /nodynamioccopyright/ + * @test /nodynamiccopyright/ * @bug 8199194 * @summary smoke test for --enabled-preview classreader support * @compile -XDforcePreview --enable-preview -source 11 Bar.java